fssm 0.1.2 → 0.1.3
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/VERSION.yml +3 -3
- data/fssm.gemspec +7 -6
- data/lib/fssm.rb +3 -10
- data/lib/fssm/backends/fsevents.rb +4 -5
- data/lib/fssm/backends/inotify.rb +7 -6
- data/lib/fssm/backends/polling.rb +2 -3
- data/lib/fssm/monitor.rb +9 -8
- data/lib/fssm/path.rb +1 -1
- data/lib/fssm/pathname.rb +149 -175
- data/lib/fssm/state/directory.rb +57 -0
- data/lib/fssm/state/file.rb +24 -0
- data/lib/fssm/support.rb +17 -6
- metadata +70 -60
- data/lib/fssm/state.rb +0 -54
data/VERSION.yml
CHANGED
data/fssm.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{fssm}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Travis Tilley"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2010-02-27}
|
13
13
|
s.description = %q{file system state monitor}
|
14
14
|
s.email = %q{ttilley@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -33,7 +33,8 @@ Gem::Specification.new do |s|
|
|
33
33
|
"lib/fssm/monitor.rb",
|
34
34
|
"lib/fssm/path.rb",
|
35
35
|
"lib/fssm/pathname.rb",
|
36
|
-
"lib/fssm/state.rb",
|
36
|
+
"lib/fssm/state/directory.rb",
|
37
|
+
"lib/fssm/state/file.rb",
|
37
38
|
"lib/fssm/support.rb",
|
38
39
|
"lib/fssm/tree.rb",
|
39
40
|
"profile/prof-cache.rb",
|
@@ -52,12 +53,12 @@ Gem::Specification.new do |s|
|
|
52
53
|
s.homepage = %q{http://github.com/ttilley/fssm}
|
53
54
|
s.rdoc_options = ["--charset=UTF-8"]
|
54
55
|
s.require_paths = ["lib"]
|
55
|
-
s.rubygems_version = %q{1.3.
|
56
|
+
s.rubygems_version = %q{1.3.6}
|
56
57
|
s.summary = %q{file system state monitor}
|
57
58
|
s.test_files = [
|
58
59
|
"spec/path_spec.rb",
|
59
|
-
"spec/
|
60
|
-
"spec/
|
60
|
+
"spec/spec_helper.rb",
|
61
|
+
"spec/root/file.rb"
|
61
62
|
]
|
62
63
|
|
63
64
|
if s.respond_to? :specification_version then
|
data/lib/fssm.rb
CHANGED
@@ -12,15 +12,7 @@ module FSSM
|
|
12
12
|
|
13
13
|
def monitor(*args, &block)
|
14
14
|
monitor = FSSM::Monitor.new
|
15
|
-
|
16
|
-
|
17
|
-
if block_given?
|
18
|
-
if block.arity == 1
|
19
|
-
block.call(context)
|
20
|
-
else
|
21
|
-
context.instance_eval(&block)
|
22
|
-
end
|
23
|
-
end
|
15
|
+
FSSM::Support.use_block(args.empty? ? monitor : monitor.path(*args), block)
|
24
16
|
|
25
17
|
monitor.run
|
26
18
|
end
|
@@ -33,7 +25,8 @@ require 'fssm/pathname'
|
|
33
25
|
require 'fssm/support'
|
34
26
|
require 'fssm/tree'
|
35
27
|
require 'fssm/path'
|
36
|
-
require 'fssm/state'
|
28
|
+
require 'fssm/state/directory'
|
29
|
+
require 'fssm/state/file'
|
37
30
|
require 'fssm/monitor'
|
38
31
|
|
39
32
|
require "fssm/backends/#{FSSM::Support.backend.downcase}"
|
@@ -7,18 +7,17 @@ module FSSM::Backends
|
|
7
7
|
@fsevents = []
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
11
|
-
handler =
|
12
|
-
@handlers["#{path}"] = handler
|
10
|
+
def add_handler(handler, preload=true)
|
11
|
+
@handlers[handler.path.to_s] = handler
|
13
12
|
|
14
|
-
fsevent = Rucola::FSEvents.new(
|
13
|
+
fsevent = Rucola::FSEvents.new(handler.path.to_s, {:latency => 0.5}) do |events|
|
15
14
|
events.each do |event|
|
16
15
|
handler.refresh(event.path)
|
17
16
|
end
|
18
17
|
end
|
19
18
|
|
20
19
|
fsevent.create_stream
|
21
|
-
handler.refresh(
|
20
|
+
handler.refresh(nil, true) if preload
|
22
21
|
fsevent.start
|
23
22
|
@fsevents << fsevent
|
24
23
|
end
|
@@ -4,14 +4,15 @@ module FSSM::Backends
|
|
4
4
|
@notifier = INotify::Notifier.new
|
5
5
|
end
|
6
6
|
|
7
|
-
def
|
8
|
-
handler
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
def add_handler(handler, preload=true)
|
8
|
+
@notifier.watch(handler.path.to_s, :recursive, :attrib, :modify, :create,
|
9
|
+
:delete, :delete_self, :moved_from, :moved_to, :move_self) do |event|
|
10
|
+
path = FSSM::Pathname.for(event.absolute_name)
|
11
|
+
path = path.dirname unless event.name == "" # Event on root directory
|
12
|
+
handler.refresh(path)
|
12
13
|
end
|
13
14
|
|
14
|
-
handler.refresh(
|
15
|
+
handler.refresh(nil, true) if preload
|
15
16
|
end
|
16
17
|
|
17
18
|
def run
|
@@ -5,9 +5,8 @@ module FSSM::Backends
|
|
5
5
|
@latency = options[:latency] || 1.5
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
9
|
-
handler
|
10
|
-
handler.refresh(path.to_pathname, true) if preload
|
8
|
+
def add_handler(handler, preload=true)
|
9
|
+
handler.refresh(nil, true) if preload
|
11
10
|
@handlers << handler
|
12
11
|
end
|
13
12
|
|
data/lib/fssm/monitor.rb
CHANGED
@@ -6,16 +6,17 @@ class FSSM::Monitor
|
|
6
6
|
|
7
7
|
def path(*args, &block)
|
8
8
|
path = FSSM::Path.new(*args)
|
9
|
+
FSSM::Support.use_block(path, block)
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
@backend.add_handler(FSSM::State::Directory.new(path))
|
12
|
+
path
|
13
|
+
end
|
14
|
+
|
15
|
+
def file(*args, &block)
|
16
|
+
path = FSSM::Path.new(*args)
|
17
|
+
FSSM::Support.use_block(path, block)
|
17
18
|
|
18
|
-
@backend.
|
19
|
+
@backend.add_handler(FSSM::State::File.new(path))
|
19
20
|
path
|
20
21
|
end
|
21
22
|
|
data/lib/fssm/path.rb
CHANGED
@@ -81,7 +81,7 @@ class FSSM::Path
|
|
81
81
|
|
82
82
|
def set_path(path)
|
83
83
|
path = FSSM::Pathname.for(path)
|
84
|
-
raise FSSM::FileNotFoundError, "#{path}" unless path.exist?
|
84
|
+
raise FSSM::FileNotFoundError, "No such file or directory - #{path}" unless path.exist?
|
85
85
|
@path = path.expand_path
|
86
86
|
end
|
87
87
|
|
data/lib/fssm/pathname.rb
CHANGED
@@ -1,65 +1,50 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require 'fileutils'
|
2
|
+
require 'find'
|
3
3
|
|
4
4
|
module FSSM
|
5
5
|
class Pathname < String
|
6
|
+
SYMLOOP_MAX = 8
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
ALT_SEPARATOR = Regexp.quote(File::ALT_SEPARATOR)
|
11
|
-
SEPARATOR_PAT = Regexp.compile("[#{SEPARATOR}#{ALT_SEPARATOR}]")
|
12
|
-
else
|
13
|
-
SEPARATOR_PAT = Regexp.compile(SEPARATOR)
|
14
|
-
end
|
15
|
-
|
16
|
-
if RUBY_PLATFORM =~ /(:?mswin|mingw|bccwin)/
|
17
|
-
PREFIX_PAT = Regexp.compile("^([A-Za-z]:#{SEPARATOR_PAT})")
|
18
|
-
else
|
19
|
-
PREFIX_PAT = Regexp.compile("^(#{SEPARATOR_PAT})")
|
20
|
-
end
|
8
|
+
ROOT = '/'.freeze
|
9
|
+
DOT = '.'.freeze
|
10
|
+
DOT_DOT = '..'.freeze
|
21
11
|
|
22
12
|
class << self
|
23
13
|
def for(path)
|
24
|
-
path
|
25
|
-
path.dememo
|
26
|
-
path
|
14
|
+
path.is_a?(::FSSM::Pathname) ? path : new("#{path}")
|
27
15
|
end
|
28
16
|
end
|
29
17
|
|
30
18
|
def initialize(path)
|
31
|
-
if path =~ %r{\0}
|
32
|
-
raise ArgumentError, "path cannot contain ASCII NULLs"
|
33
|
-
end
|
34
|
-
|
35
|
-
dememo
|
36
|
-
|
19
|
+
raise ArgumentError, "path cannot contain ASCII NULLs" if path =~ %r{\0}
|
37
20
|
super(path)
|
38
21
|
end
|
39
22
|
|
40
|
-
def
|
41
|
-
self
|
23
|
+
def <=>(other)
|
24
|
+
self.tr('/', "\0").to_s <=> other.to_str.tr('/', "\0")
|
25
|
+
rescue NoMethodError
|
26
|
+
nil
|
42
27
|
end
|
43
28
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
29
|
+
def ==(other)
|
30
|
+
left = self.cleanpath.tr('/', "\0").to_s
|
31
|
+
right = self.class.for(other).cleanpath.tr('/', "\0").to_s
|
47
32
|
|
48
|
-
|
33
|
+
left == right
|
34
|
+
rescue NoMethodError
|
35
|
+
false
|
36
|
+
end
|
49
37
|
|
50
|
-
def
|
51
|
-
|
52
|
-
set_prefix_and_names
|
53
|
-
@segments = @names.dup
|
54
|
-
@segments.delete('.')
|
55
|
-
@segments.unshift(@prefix) unless @prefix.empty?
|
56
|
-
@segments
|
38
|
+
def +(path)
|
39
|
+
dup << path
|
57
40
|
end
|
58
41
|
|
59
|
-
|
42
|
+
def <<(path)
|
43
|
+
replace( join(path).cleanpath! )
|
44
|
+
end
|
60
45
|
|
61
|
-
def
|
62
|
-
|
46
|
+
def absolute?
|
47
|
+
self[0, 1].to_s == ROOT
|
63
48
|
end
|
64
49
|
|
65
50
|
def ascend
|
@@ -69,37 +54,8 @@ module FSSM
|
|
69
54
|
end
|
70
55
|
end
|
71
56
|
|
72
|
-
def
|
73
|
-
|
74
|
-
1.upto(parts.length) do |i|
|
75
|
-
yield self.class.join(parts[0, i])
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def root?
|
80
|
-
set_prefix_and_names
|
81
|
-
@names.empty? && !@prefix.empty?
|
82
|
-
end
|
83
|
-
|
84
|
-
def parent
|
85
|
-
self + '..'
|
86
|
-
end
|
87
|
-
|
88
|
-
def relative?
|
89
|
-
set_prefix_and_names
|
90
|
-
@prefix.empty?
|
91
|
-
end
|
92
|
-
|
93
|
-
def absolute?
|
94
|
-
!relative?
|
95
|
-
end
|
96
|
-
|
97
|
-
def +(path)
|
98
|
-
dup << path
|
99
|
-
end
|
100
|
-
|
101
|
-
def <<(path)
|
102
|
-
replace(join(path).cleanpath!)
|
57
|
+
def children
|
58
|
+
entries[2..-1]
|
103
59
|
end
|
104
60
|
|
105
61
|
def cleanpath!
|
@@ -108,14 +64,16 @@ module FSSM
|
|
108
64
|
|
109
65
|
parts.each do |part|
|
110
66
|
case part
|
111
|
-
when
|
67
|
+
when DOT then
|
112
68
|
next
|
113
|
-
when
|
69
|
+
when DOT_DOT then
|
114
70
|
case final.last
|
115
|
-
when
|
116
|
-
|
117
|
-
when
|
118
|
-
final.push(
|
71
|
+
when ROOT then
|
72
|
+
next
|
73
|
+
when DOT_DOT then
|
74
|
+
final.push(DOT_DOT)
|
75
|
+
when nil then
|
76
|
+
final.push(DOT_DOT)
|
119
77
|
else
|
120
78
|
final.pop
|
121
79
|
end
|
@@ -124,142 +82,128 @@ module FSSM
|
|
124
82
|
end
|
125
83
|
end
|
126
84
|
|
127
|
-
replace(final.empty? ?
|
85
|
+
replace(final.empty? ? DOT : self.class.join(*final))
|
128
86
|
end
|
129
87
|
|
130
88
|
def cleanpath
|
131
89
|
dup.cleanpath!
|
132
90
|
end
|
133
91
|
|
134
|
-
def
|
135
|
-
|
92
|
+
def descend
|
93
|
+
parts = to_a
|
94
|
+
1.upto(parts.length) { |i| yield self.class.join(parts[0, i]) }
|
95
|
+
end
|
136
96
|
|
137
|
-
|
138
|
-
|
97
|
+
def dot?
|
98
|
+
self == DOT
|
99
|
+
end
|
139
100
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
end
|
101
|
+
def dot_dot?
|
102
|
+
self == DOT_DOT
|
103
|
+
end
|
144
104
|
|
145
|
-
|
146
|
-
|
147
|
-
|
105
|
+
def each_filename(&blk)
|
106
|
+
to_a.each(&blk)
|
107
|
+
end
|
108
|
+
|
109
|
+
def mountpoint?
|
110
|
+
stat1 = self.lstat
|
111
|
+
stat2 = self.parent.lstat
|
112
|
+
|
113
|
+
stat1.dev != stat2.dev || stat1.ino == stat2.ino
|
114
|
+
rescue Errno::ENOENT
|
115
|
+
false
|
116
|
+
end
|
117
|
+
|
118
|
+
def parent
|
119
|
+
self + '..'
|
120
|
+
end
|
121
|
+
|
122
|
+
def realpath
|
123
|
+
path = self
|
124
|
+
|
125
|
+
SYMLOOP_MAX.times do
|
126
|
+
link = path.readlink
|
127
|
+
link = path.dirname + link if link.relative?
|
128
|
+
path = link
|
148
129
|
end
|
130
|
+
|
131
|
+
raise Errno::ELOOP, self
|
132
|
+
rescue Errno::EINVAL
|
133
|
+
path.expand_path
|
134
|
+
end
|
135
|
+
|
136
|
+
def relative?
|
137
|
+
!absolute?
|
149
138
|
end
|
150
139
|
|
151
140
|
def relative_path_from(base)
|
152
141
|
base = self.class.for(base)
|
153
142
|
|
154
|
-
if self.absolute? != base.absolute?
|
155
|
-
raise ArgumentError, 'no relative path between a relative and absolute'
|
156
|
-
end
|
143
|
+
raise ArgumentError, 'no relative path between a relative and absolute' if self.absolute? != base.absolute?
|
157
144
|
|
158
|
-
|
159
|
-
|
160
|
-
end
|
145
|
+
return self if base.dot?
|
146
|
+
return self.class.new(DOT) if self == base
|
161
147
|
|
162
|
-
base = base.cleanpath
|
163
|
-
dest =
|
148
|
+
base = base.cleanpath.to_a
|
149
|
+
dest = self.cleanpath.to_a
|
164
150
|
|
165
151
|
while !dest.empty? && !base.empty? && dest[0] == base[0]
|
166
152
|
base.shift
|
167
153
|
dest.shift
|
168
154
|
end
|
169
155
|
|
170
|
-
base.shift if base[0] ==
|
171
|
-
dest.shift if dest[0] ==
|
156
|
+
base.shift if base[0] == DOT
|
157
|
+
dest.shift if dest[0] == DOT
|
172
158
|
|
173
|
-
if base.include?(
|
174
|
-
raise ArgumentError, "base directory may not contain '..'"
|
175
|
-
end
|
159
|
+
raise ArgumentError, "base directory may not contain '#{DOT_DOT}'" if base.include?(DOT_DOT)
|
176
160
|
|
177
|
-
path = base.fill(
|
161
|
+
path = base.fill(DOT_DOT) + dest
|
178
162
|
path = self.class.join(*path)
|
179
|
-
path = self.class.new(
|
163
|
+
path = self.class.new(DOT) if path.empty?
|
180
164
|
|
181
165
|
path
|
182
166
|
end
|
183
167
|
|
184
|
-
def
|
185
|
-
|
186
|
-
raise ArgumentError, "path cannot contain ASCII NULLs"
|
187
|
-
end
|
188
|
-
|
189
|
-
dememo
|
190
|
-
|
191
|
-
super(path)
|
168
|
+
def root?
|
169
|
+
!!(self =~ %r{^#{ROOT}+$})
|
192
170
|
end
|
193
171
|
|
194
|
-
def
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
true
|
172
|
+
def to_a
|
173
|
+
array = to_s.split(File::SEPARATOR)
|
174
|
+
array.delete('')
|
175
|
+
array.insert(0, ROOT) if absolute?
|
176
|
+
array
|
200
177
|
end
|
201
178
|
|
202
|
-
|
203
|
-
set_prefix_and_names
|
204
|
-
@prefix
|
205
|
-
end
|
179
|
+
alias segments to_a
|
206
180
|
|
207
|
-
def
|
208
|
-
|
209
|
-
@names
|
181
|
+
def to_path
|
182
|
+
self
|
210
183
|
end
|
211
184
|
|
212
|
-
def
|
213
|
-
|
214
|
-
@segments = nil
|
215
|
-
@prefix = nil
|
216
|
-
@names = nil
|
185
|
+
def to_s
|
186
|
+
"#{self}"
|
217
187
|
end
|
218
188
|
|
219
|
-
|
220
|
-
|
221
|
-
def set_prefix_and_names
|
222
|
-
return if @set
|
223
|
-
|
224
|
-
@names = []
|
225
|
-
|
226
|
-
if (match = PREFIX_PAT.match(self))
|
227
|
-
@prefix = match[0].to_s
|
228
|
-
@names += match.post_match.split(SEPARATOR_PAT)
|
229
|
-
else
|
230
|
-
@prefix = ''
|
231
|
-
@names += self.split(SEPARATOR_PAT)
|
232
|
-
end
|
233
|
-
|
234
|
-
@names.compact!
|
235
|
-
@names.delete('')
|
189
|
+
alias to_str to_s
|
236
190
|
|
237
|
-
|
191
|
+
def unlink
|
192
|
+
Dir.unlink(self)
|
193
|
+
true
|
194
|
+
rescue Errno::ENOTDIR
|
195
|
+
File.unlink(self)
|
196
|
+
true
|
238
197
|
end
|
239
|
-
|
240
198
|
end
|
241
199
|
|
242
200
|
class Pathname
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
dirs.map! {|path| new(path)}
|
247
|
-
|
248
|
-
if block_given?
|
249
|
-
dirs.each {|dir| yield dir}
|
250
|
-
nil
|
251
|
-
else
|
252
|
-
dirs
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
def [](pattern)
|
257
|
-
Dir[pattern].map! {|path| new(path)}
|
258
|
-
end
|
201
|
+
def self.[](pattern)
|
202
|
+
Dir[pattern].map! {|d| FSSM::Pathname.new(d) }
|
203
|
+
end
|
259
204
|
|
260
|
-
|
261
|
-
|
262
|
-
end
|
205
|
+
def self.pwd
|
206
|
+
FSSM::Pathname.new(Dir.pwd)
|
263
207
|
end
|
264
208
|
|
265
209
|
def entries
|
@@ -278,6 +222,24 @@ module FSSM
|
|
278
222
|
Dir.rmdir(self)
|
279
223
|
end
|
280
224
|
|
225
|
+
def self.glob(pattern, flags = 0)
|
226
|
+
dirs = Dir.glob(pattern, flags)
|
227
|
+
dirs.map! {|path| FSSM::Pathname.new(path) }
|
228
|
+
|
229
|
+
if block_given?
|
230
|
+
dirs.each {|dir| yield dir }
|
231
|
+
nil
|
232
|
+
else
|
233
|
+
dirs
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def glob(pattern, flags = 0, &block)
|
238
|
+
patterns = [pattern].flatten
|
239
|
+
patterns.map! {|p| self.class.glob(self.to_s + p, flags, &block) }
|
240
|
+
patterns.flatten
|
241
|
+
end
|
242
|
+
|
281
243
|
def chdir
|
282
244
|
blk = lambda { yield self } if block_given?
|
283
245
|
Dir.chdir(self, &blk)
|
@@ -372,8 +334,6 @@ module FSSM
|
|
372
334
|
def zero?
|
373
335
|
FileTest.zero?(self)
|
374
336
|
end
|
375
|
-
|
376
|
-
alias exist? exists?
|
377
337
|
end
|
378
338
|
|
379
339
|
class Pathname
|
@@ -407,10 +367,10 @@ module FSSM
|
|
407
367
|
end
|
408
368
|
|
409
369
|
class Pathname
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
370
|
+
def self.join(*parts)
|
371
|
+
last_part = FSSM::Pathname.new(parts.last)
|
372
|
+
return last_part if last_part.absolute?
|
373
|
+
FSSM::Pathname.new(File.join(*parts.reject {|p| p.empty? }))
|
414
374
|
end
|
415
375
|
|
416
376
|
def basename
|
@@ -478,6 +438,10 @@ module FSSM
|
|
478
438
|
File.size?(self)
|
479
439
|
end
|
480
440
|
|
441
|
+
def split
|
442
|
+
File.split(self).map {|part| FSSM::Pathname.new(part) }
|
443
|
+
end
|
444
|
+
|
481
445
|
def symlink(to)
|
482
446
|
File.symlink(self, to)
|
483
447
|
end
|
@@ -525,4 +489,14 @@ module FSSM
|
|
525
489
|
end
|
526
490
|
end
|
527
491
|
|
492
|
+
class Pathname
|
493
|
+
class << self
|
494
|
+
alias getwd pwd
|
495
|
+
end
|
496
|
+
|
497
|
+
alias absolute expand_path
|
498
|
+
alias delete unlink
|
499
|
+
alias exist? exists?
|
500
|
+
alias fnmatch fnmatch?
|
501
|
+
end
|
528
502
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module FSSM::State
|
2
|
+
class Directory
|
3
|
+
attr_reader :path
|
4
|
+
|
5
|
+
def initialize(path)
|
6
|
+
@path = path
|
7
|
+
@cache = FSSM::Tree::Cache.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def refresh(base=nil, skip_callbacks=false)
|
11
|
+
previous, current = recache(base || @path.to_pathname)
|
12
|
+
|
13
|
+
unless skip_callbacks
|
14
|
+
deleted(previous, current)
|
15
|
+
created(previous, current)
|
16
|
+
modified(previous, current)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def created(previous, current)
|
23
|
+
(current.keys - previous.keys).each {|created| @path.create(created)}
|
24
|
+
end
|
25
|
+
|
26
|
+
def deleted(previous, current)
|
27
|
+
(previous.keys - current.keys).each {|deleted| @path.delete(deleted)}
|
28
|
+
end
|
29
|
+
|
30
|
+
def modified(previous, current)
|
31
|
+
(current.keys & previous.keys).each do |file|
|
32
|
+
@path.update(file) if (current[file] <=> previous[file]) != 0
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def recache(base)
|
37
|
+
base = FSSM::Pathname.for(base)
|
38
|
+
previous = @cache.files
|
39
|
+
snapshot(base)
|
40
|
+
current = @cache.files
|
41
|
+
[previous, current]
|
42
|
+
end
|
43
|
+
|
44
|
+
def snapshot(base)
|
45
|
+
base = FSSM::Pathname.for(base)
|
46
|
+
@cache.unset(base)
|
47
|
+
@path.glob.each {|glob| add_glob(base, glob)}
|
48
|
+
end
|
49
|
+
|
50
|
+
def add_glob(base, glob)
|
51
|
+
FSSM::Pathname.glob(base.join(glob).to_s).each do |fn|
|
52
|
+
@cache.set(fn)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module FSSM::State
|
2
|
+
class File
|
3
|
+
attr_reader :path
|
4
|
+
|
5
|
+
def initialize(path)
|
6
|
+
@path = path
|
7
|
+
end
|
8
|
+
|
9
|
+
def refresh(base=nil, skip_callbacks=false)
|
10
|
+
base ||= @path.to_pathname
|
11
|
+
used_to_exist, @exists = @exists, base.exists?
|
12
|
+
# this handles bad symlinks without failing. why handle bad symlinks at
|
13
|
+
# all? well, we could still be interested in their creation and deletion.
|
14
|
+
old_mtime, @mtime = @mtime, base.symlink? ? Time.at(0) : base.mtime if @exists
|
15
|
+
|
16
|
+
unless skip_callbacks
|
17
|
+
@path.delete(@path.to_s) if used_to_exist && !@exists
|
18
|
+
@path.create(@path.to_s) if !used_to_exist && @exists
|
19
|
+
@path.update(@path.to_s) if used_to_exist && @exists && old_mtime != @mtime
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
data/lib/fssm/support.rb
CHANGED
@@ -37,15 +37,26 @@ module FSSM::Support
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def rb_inotify?
|
40
|
-
begin
|
41
|
-
require 'rubygems'
|
42
|
-
gem 'rb-inotify', '>= 0.3.0'
|
40
|
+
found = begin
|
43
41
|
require 'rb-inotify'
|
44
|
-
|
45
|
-
|
46
|
-
|
42
|
+
if defined?(INotify::VERSION)
|
43
|
+
version = INotify::VERSION
|
44
|
+
version[0] > 0 || version[1] >= 6
|
45
|
+
end
|
46
|
+
rescue LoadError
|
47
47
|
false
|
48
48
|
end
|
49
|
+
STDERR.puts("Warning: Unable to load rb-inotify >= 0.5.1. Inotify will be unavailable.") unless found
|
50
|
+
found
|
51
|
+
end
|
52
|
+
|
53
|
+
def use_block(context, block)
|
54
|
+
return if block.nil?
|
55
|
+
if block.arity == 1
|
56
|
+
block.call(context)
|
57
|
+
else
|
58
|
+
context.instance_eval(&block)
|
59
|
+
end
|
49
60
|
end
|
50
61
|
|
51
62
|
end
|
metadata
CHANGED
@@ -1,27 +1,34 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fssm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 3
|
9
|
+
version: 0.1.3
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
|
-
- Travis Tilley
|
12
|
+
- Travis Tilley
|
8
13
|
autorequire:
|
9
14
|
bindir: bin
|
10
15
|
cert_chain: []
|
11
16
|
|
12
|
-
date:
|
17
|
+
date: 2010-02-27 00:00:00 -05:00
|
13
18
|
default_executable:
|
14
19
|
dependencies:
|
15
|
-
- !ruby/object:Gem::Dependency
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rspec
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :development
|
31
|
+
version_requirements: *id001
|
25
32
|
description: file system state monitor
|
26
33
|
email: ttilley@gmail.com
|
27
34
|
executables: []
|
@@ -29,69 +36,72 @@ executables: []
|
|
29
36
|
extensions: []
|
30
37
|
|
31
38
|
extra_rdoc_files:
|
32
|
-
- LICENSE
|
33
|
-
- README.markdown
|
39
|
+
- LICENSE
|
40
|
+
- README.markdown
|
34
41
|
files:
|
35
|
-
- .document
|
36
|
-
- .gitignore
|
37
|
-
- LICENSE
|
38
|
-
- README.markdown
|
39
|
-
- Rakefile
|
40
|
-
- VERSION.yml
|
41
|
-
- example.rb
|
42
|
-
- fssm.gemspec
|
43
|
-
- lib/fssm.rb
|
44
|
-
- lib/fssm/backends/fsevents.rb
|
45
|
-
- lib/fssm/backends/inotify.rb
|
46
|
-
- lib/fssm/backends/polling.rb
|
47
|
-
- lib/fssm/backends/rubycocoa/fsevents.rb
|
48
|
-
- lib/fssm/monitor.rb
|
49
|
-
- lib/fssm/path.rb
|
50
|
-
- lib/fssm/pathname.rb
|
51
|
-
- lib/fssm/state.rb
|
52
|
-
- lib/fssm/
|
53
|
-
- lib/fssm/
|
54
|
-
-
|
55
|
-
- profile/prof-
|
56
|
-
- profile/prof-pathname.
|
57
|
-
- profile/prof-
|
58
|
-
- profile/prof.html
|
59
|
-
-
|
60
|
-
- spec/
|
61
|
-
- spec/root/
|
62
|
-
- spec/root/file.
|
63
|
-
- spec/root/file.
|
64
|
-
- spec/root/
|
65
|
-
- spec/
|
42
|
+
- .document
|
43
|
+
- .gitignore
|
44
|
+
- LICENSE
|
45
|
+
- README.markdown
|
46
|
+
- Rakefile
|
47
|
+
- VERSION.yml
|
48
|
+
- example.rb
|
49
|
+
- fssm.gemspec
|
50
|
+
- lib/fssm.rb
|
51
|
+
- lib/fssm/backends/fsevents.rb
|
52
|
+
- lib/fssm/backends/inotify.rb
|
53
|
+
- lib/fssm/backends/polling.rb
|
54
|
+
- lib/fssm/backends/rubycocoa/fsevents.rb
|
55
|
+
- lib/fssm/monitor.rb
|
56
|
+
- lib/fssm/path.rb
|
57
|
+
- lib/fssm/pathname.rb
|
58
|
+
- lib/fssm/state/directory.rb
|
59
|
+
- lib/fssm/state/file.rb
|
60
|
+
- lib/fssm/support.rb
|
61
|
+
- lib/fssm/tree.rb
|
62
|
+
- profile/prof-cache.rb
|
63
|
+
- profile/prof-fssm-pathname.html
|
64
|
+
- profile/prof-pathname.rb
|
65
|
+
- profile/prof-plain-pathname.html
|
66
|
+
- profile/prof.html
|
67
|
+
- spec/path_spec.rb
|
68
|
+
- spec/root/duck/quack.txt
|
69
|
+
- spec/root/file.css
|
70
|
+
- spec/root/file.rb
|
71
|
+
- spec/root/file.yml
|
72
|
+
- spec/root/moo/cow.txt
|
73
|
+
- spec/spec_helper.rb
|
66
74
|
has_rdoc: true
|
67
75
|
homepage: http://github.com/ttilley/fssm
|
68
76
|
licenses: []
|
69
77
|
|
70
78
|
post_install_message:
|
71
79
|
rdoc_options:
|
72
|
-
- --charset=UTF-8
|
80
|
+
- --charset=UTF-8
|
73
81
|
require_paths:
|
74
|
-
- lib
|
82
|
+
- lib
|
75
83
|
required_ruby_version: !ruby/object:Gem::Requirement
|
76
84
|
requirements:
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
segments:
|
88
|
+
- 0
|
89
|
+
version: "0"
|
81
90
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
91
|
requirements:
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
segments:
|
95
|
+
- 0
|
96
|
+
version: "0"
|
87
97
|
requirements: []
|
88
98
|
|
89
99
|
rubyforge_project:
|
90
|
-
rubygems_version: 1.3.
|
100
|
+
rubygems_version: 1.3.6
|
91
101
|
signing_key:
|
92
102
|
specification_version: 3
|
93
103
|
summary: file system state monitor
|
94
104
|
test_files:
|
95
|
-
- spec/path_spec.rb
|
96
|
-
- spec/
|
97
|
-
- spec/
|
105
|
+
- spec/path_spec.rb
|
106
|
+
- spec/spec_helper.rb
|
107
|
+
- spec/root/file.rb
|
data/lib/fssm/state.rb
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
class FSSM::State
|
3
|
-
def initialize(path)
|
4
|
-
@path = path
|
5
|
-
@cache = FSSM::Tree::Cache.new
|
6
|
-
end
|
7
|
-
|
8
|
-
def refresh(base=nil, skip_callbacks=false)
|
9
|
-
previous, current = recache(base || @path.to_pathname)
|
10
|
-
|
11
|
-
unless skip_callbacks
|
12
|
-
deleted(previous, current)
|
13
|
-
created(previous, current)
|
14
|
-
modified(previous, current)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def created(previous, current)
|
21
|
-
(current.keys - previous.keys).each {|created| @path.create(created)}
|
22
|
-
end
|
23
|
-
|
24
|
-
def deleted(previous, current)
|
25
|
-
(previous.keys - current.keys).each {|deleted| @path.delete(deleted)}
|
26
|
-
end
|
27
|
-
|
28
|
-
def modified(previous, current)
|
29
|
-
(current.keys & previous.keys).each do |file|
|
30
|
-
@path.update(file) if (current[file] <=> previous[file]) != 0
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def recache(base)
|
35
|
-
base = FSSM::Pathname.for(base)
|
36
|
-
previous = @cache.files
|
37
|
-
snapshot(base)
|
38
|
-
current = @cache.files
|
39
|
-
[previous, current]
|
40
|
-
end
|
41
|
-
|
42
|
-
def snapshot(base)
|
43
|
-
base = FSSM::Pathname.for(base)
|
44
|
-
@cache.unset(base)
|
45
|
-
@path.glob.each {|glob| add_glob(base, glob)}
|
46
|
-
end
|
47
|
-
|
48
|
-
def add_glob(base, glob)
|
49
|
-
FSSM::Pathname.glob(base.join(glob).to_s).each do |fn|
|
50
|
-
@cache.set(fn)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|