fssm 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,25 @@
1
+ class FSSM::Monitor
2
+ def initialize(options={})
3
+ @options = options
4
+ @backend = FSSM::Backends::Default.new
5
+ end
6
+
7
+ def path(*args, &block)
8
+ path = FSSM::Path.new(*args)
9
+
10
+ if block_given?
11
+ if block.arity == 1
12
+ block.call(path)
13
+ else
14
+ path.instance_eval(&block)
15
+ end
16
+ end
17
+
18
+ @backend.add_path(path)
19
+ path
20
+ end
21
+
22
+ def run
23
+ @backend.run
24
+ end
25
+ end
@@ -0,0 +1,91 @@
1
+ class FSSM::Path
2
+ def initialize(path=nil, glob=nil, &block)
3
+ set_path(path || '.')
4
+ set_glob(glob || '**/*')
5
+ init_callbacks
6
+
7
+ if block_given?
8
+ if block.arity == 1
9
+ block.call(self)
10
+ else
11
+ self.instance_eval(&block)
12
+ end
13
+ end
14
+ end
15
+
16
+ def to_s
17
+ @path.to_s
18
+ end
19
+
20
+ def to_pathname
21
+ @path
22
+ end
23
+
24
+ def glob(value=nil)
25
+ return @glob if value.nil?
26
+ set_glob(value)
27
+ end
28
+
29
+ def create(callback_or_path=nil, &block)
30
+ callback_action(:create, (block_given? ? block : callback_or_path))
31
+ end
32
+
33
+ def update(callback_or_path=nil, &block)
34
+ callback_action(:update, (block_given? ? block : callback_or_path))
35
+ end
36
+
37
+ def delete(callback_or_path=nil, &block)
38
+ callback_action(:delete, (block_given? ? block : callback_or_path))
39
+ end
40
+
41
+ private
42
+
43
+ def init_callbacks
44
+ do_nothing = lambda {|base, relative|}
45
+ @callbacks = Hash.new(do_nothing)
46
+ end
47
+
48
+ def callback_action(type, arg=nil)
49
+ if arg.is_a?(Proc)
50
+ set_callback(type, arg)
51
+ elsif arg.nil?
52
+ get_callback(type)
53
+ else
54
+ run_callback(type, arg)
55
+ end
56
+ end
57
+
58
+ def set_callback(type, arg)
59
+ raise ArgumentError, "Proc expected" unless arg.is_a?(Proc)
60
+ @callbacks[type] = arg
61
+ end
62
+
63
+ def get_callback(type)
64
+ @callbacks[type]
65
+ end
66
+
67
+ def run_callback(type, arg)
68
+ base, relative = split_path(arg)
69
+
70
+ begin
71
+ @callbacks[type].call(base, relative)
72
+ rescue Exception => e
73
+ raise FSSM::CallbackError, "#{type} - #{base.join(relative)}: #{e.message}", e.backtrace
74
+ end
75
+ end
76
+
77
+ def split_path(path)
78
+ path = FSSM::Pathname.for(path)
79
+ [@path, (path.relative? ? path : path.relative_path_from(@path))]
80
+ end
81
+
82
+ def set_path(path)
83
+ path = FSSM::Pathname.for(path)
84
+ raise FSSM::FileNotFoundError, "#{path}" unless path.exist?
85
+ @path = path.expand_path
86
+ end
87
+
88
+ def set_glob(glob)
89
+ @glob = glob.is_a?(Array) ? glob : [glob]
90
+ end
91
+ end
@@ -0,0 +1,350 @@
1
+ # The bundled ruby pathname library is a slow and hideous beast.
2
+ # There. I said it. This version is based on pathname3.
3
+
4
+ module FSSM
5
+ class Pathname < String
6
+
7
+ SEPARATOR = Regexp.quote(File::SEPARATOR)
8
+
9
+ if File::ALT_SEPARATOR
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
21
+
22
+ class << self
23
+ def for(path)
24
+ path = path.is_a?(::FSSM::Pathname) ? path : new(path)
25
+ path.dememo
26
+ path
27
+ end
28
+ end
29
+
30
+ def initialize(path)
31
+ if path =~ %r{\0}
32
+ raise ArgumentError, "path cannot contain ASCII NULLs"
33
+ end
34
+
35
+ dememo
36
+
37
+ super(path)
38
+ end
39
+
40
+ def to_path
41
+ self
42
+ end
43
+
44
+ def to_s
45
+ "#{self}"
46
+ end
47
+ alias to_str to_s
48
+
49
+ def to_a
50
+ return @segments if @segments
51
+ set_prefix_and_names
52
+ @segments = @names.dup
53
+ @segments.delete('.')
54
+ @segments.unshift(@prefix) unless @prefix.empty?
55
+ @segments
56
+ end
57
+ alias segments to_a
58
+
59
+ def each_filename(&block)
60
+ to_a.each(&block)
61
+ end
62
+
63
+ def ascend
64
+ parts = to_a
65
+ parts.length.downto(1) do |i|
66
+ yield self.class.join(parts[0, i])
67
+ end
68
+ end
69
+
70
+ def descend
71
+ parts = to_a
72
+ 1.upto(parts.length) do |i|
73
+ yield self.class.join(parts[0, i])
74
+ end
75
+ end
76
+
77
+ def root?
78
+ set_prefix_and_names
79
+ @names.empty? && !@prefix.empty?
80
+ end
81
+
82
+ def parent
83
+ self + '..'
84
+ end
85
+
86
+ def relative?
87
+ set_prefix_and_names
88
+ @prefix.empty?
89
+ end
90
+
91
+ def absolute?
92
+ !relative?
93
+ end
94
+
95
+ def +(path)
96
+ dup << path
97
+ end
98
+
99
+ def <<(path)
100
+ replace(join(path).cleanpath!)
101
+ end
102
+
103
+ def cleanpath!
104
+ parts = to_a
105
+ final = []
106
+
107
+ parts.each do |part|
108
+ case part
109
+ when '.' then next
110
+ when '..' then
111
+ case final.last
112
+ when '..' then final.push('..')
113
+ when nil then final.push('..')
114
+ else final.pop
115
+ end
116
+ else final.push(part)
117
+ end
118
+ end
119
+
120
+ replace(final.empty? ? Dir.pwd : File.join(*final))
121
+ end
122
+
123
+ def cleanpath
124
+ dup.cleanpath!
125
+ end
126
+
127
+ def realpath
128
+ raise unless self.exist?
129
+
130
+ if File.symlink?(self)
131
+ file = self.dup
132
+
133
+ while true
134
+ file = File.join(File.dirname(file), File.readlink(file))
135
+ break unless File.symlink?(file)
136
+ end
137
+
138
+ self.class.new(file).clean
139
+ else
140
+ self.class.new(Dir.pwd) + self
141
+ end
142
+ end
143
+
144
+ def relative_path_from(base)
145
+ base = self.class.for(base)
146
+
147
+ if self.absolute? != base.absolute?
148
+ raise ArgumentError, 'no relative path between a relative and absolute'
149
+ end
150
+
151
+ if self.prefix != base.prefix
152
+ raise ArgumentError, "different prefix: #{@prefix.inspect} and #{base.prefix.inspect}"
153
+ end
154
+
155
+ base = base.cleanpath!.segments
156
+ dest = dup.cleanpath!.segments
157
+
158
+ while !dest.empty? && !base.empty? && dest[0] == base[0]
159
+ base.shift
160
+ dest.shift
161
+ end
162
+
163
+ base.shift if base[0] == '.'
164
+ dest.shift if dest[0] == '.'
165
+
166
+ if base.include?('..')
167
+ raise ArgumentError, "base directory may not contain '..'"
168
+ end
169
+
170
+ path = base.fill('..') + dest
171
+ path = self.class.join(*path)
172
+ path = self.class.new('.') if path.empty?
173
+
174
+ path
175
+ end
176
+
177
+ def replace(path)
178
+ if path =~ %r{\0}
179
+ raise ArgumentError, "path cannot contain ASCII NULLs"
180
+ end
181
+
182
+ dememo
183
+
184
+ super(path)
185
+ end
186
+
187
+ def unlink
188
+ Dir.unlink(self)
189
+ true
190
+ rescue Errno::ENOTDIR
191
+ File.unlink(self)
192
+ true
193
+ end
194
+
195
+ def prefix
196
+ set_prefix_and_names
197
+ @prefix
198
+ end
199
+
200
+ def names
201
+ set_prefix_and_names
202
+ @names
203
+ end
204
+
205
+ def dememo
206
+ @set = nil
207
+ @segments = nil
208
+ @prefix = nil
209
+ @names = nil
210
+ end
211
+
212
+ private
213
+
214
+ def set_prefix_and_names
215
+ return if @set
216
+
217
+ @names = []
218
+
219
+ if (match = PREFIX_PAT.match(self))
220
+ @prefix = match[0].to_s
221
+ @names += match.post_match.split(SEPARATOR_PAT)
222
+ else
223
+ @prefix = ''
224
+ @names += self.split(SEPARATOR_PAT)
225
+ end
226
+
227
+ @names.compact!
228
+ @names.delete('')
229
+
230
+ @set = true
231
+ end
232
+
233
+ end
234
+
235
+ class Pathname
236
+ class << self
237
+ def glob(pattern, flags=0)
238
+ dirs = Dir.glob(pattern, flags)
239
+ dirs.map! {|path| new(path)}
240
+
241
+ if block_given?
242
+ dirs.each {|dir| yield dir}
243
+ nil
244
+ else
245
+ dirs
246
+ end
247
+ end
248
+
249
+ def [](pattern)
250
+ Dir[pattern].map! {|path| new(path)}
251
+ end
252
+
253
+ def pwd
254
+ new(Dir.pwd)
255
+ end
256
+ end
257
+
258
+ def entries; Dir.entries(self).map! {|e| FSSM::Pathname.new(e) }; end
259
+ def mkdir(mode = 0777); Dir.mkdir(self, mode); end
260
+ def opendir(&blk); Dir.open(self, &blk); end
261
+ def rmdir; Dir.rmdir(self); end
262
+
263
+ def chdir
264
+ blk = lambda { yield self } if block_given?
265
+ Dir.chdir(self, &blk)
266
+ end
267
+ end
268
+
269
+ class Pathname
270
+ def blockdev?; FileTest.blockdev?(self); end
271
+ def chardev?; FileTest.chardev?(self); end
272
+ def directory?; FileTest.directory?(self); end
273
+ def executable?; FileTest.executable?(self); end
274
+ def executable_real?; FileTest.executable_real?(self); end
275
+ def exists?; FileTest.exists?(self); end
276
+ def file?; FileTest.file?(self); end
277
+ def grpowned?; FileTest.grpowned?(self); end
278
+ def owned?; FileTest.owned?(self); end
279
+ def pipe?; FileTest.pipe?(self); end
280
+ def readable?; FileTest.readable?(self); end
281
+ def readable_real?; FileTest.readable_real?(self); end
282
+ def setgid?; FileTest.setgit?(self); end
283
+ def setuid?; FileTest.setuid?(self); end
284
+ def socket?; FileTest.socket?(self); end
285
+ def sticky?; FileTest.sticky?(self); end
286
+ def symlink?; FileTest.symlink?(self); end
287
+ def world_readable?; FileTest.world_readable?(self); end
288
+ def world_writable?; FileTest.world_writable?(self); end
289
+ def writable?; FileTest.writable?(self); end
290
+ def writable_real?; FileTest.writable_real?(self); end
291
+ def zero?; FileTest.zero?(self); end
292
+
293
+ alias exist? exists?
294
+ end
295
+
296
+ class Pathname
297
+ def atime; File.atime(self); end
298
+ def ctime; File.ctime(self); end
299
+ def ftype; File.ftype(self); end
300
+ def lstat; File.lstat(self); end
301
+ def mtime; File.mtime(self); end
302
+ def stat; File.stat(self); end
303
+ def utime(atime, mtime); File.utime(self, atime, mtime); end
304
+ end
305
+
306
+ class Pathname
307
+ class << self
308
+ def join(*parts)
309
+ new(File.join(*parts.reject {|p| p.empty? }))
310
+ end
311
+ end
312
+
313
+ def basename; self.class.new(File.basename(self)); end
314
+ def chmod(mode); File.chmod(mode, self); end
315
+ def chown(owner, group); File.chown(owner, group, self); end
316
+ def dirname; self.class.new(File.dirname(self)); end
317
+ def expand_path(from = nil); self.class.new(File.expand_path(self, from)); end
318
+ def extname; File.extname(self); end
319
+ def fnmatch?(pat, flags = 0); File.fnmatch(pat, self, flags); end
320
+ def join(*parts); self.class.join(self, *parts); end
321
+ def lchmod(mode); File.lchmod(mode, self); end
322
+ def lchown(owner, group); File.lchown(owner, group, self); end
323
+ def link(to); File.link(self, to); end
324
+ def open(mode = 'r', perm = nil, &blk); File.open(self, mode, perm, &blk); end
325
+ def readlink; self.class.new(File.readlink(self)); end
326
+ def rename(to); File.rename(self, to); replace(to); end
327
+ def size; File.size(self); end
328
+ def size?; File.size?(self); end
329
+ def symlink(to); File.symlink(self, to); end
330
+ def truncate; File.truncate(self); end
331
+ end
332
+
333
+ class Pathname
334
+ def mkpath; self.class.new(FileUtils.mkpath(self)); end
335
+ def rmtree; self.class.new(FileUtils.rmtree(self).first); end
336
+ def touch; self.class.new(FileUtils.touch(self).first); end
337
+ end
338
+
339
+ class Pathname
340
+ def each_line(sep = $/, &blk); IO.foreach(self, sep, &blk); end
341
+ def read(len = nil, off = 0); IO.read(self, len, off); end
342
+ def readlines(sep = $/); IO.readlines(self, sep); end
343
+ def sysopen(mode = 'r', perm = nil); IO.sysopen(self, mode, perm); end
344
+ end
345
+
346
+ class Pathname
347
+ def find; Find.find(self) {|path| yield FSSM::Pathname.new(path) }; end
348
+ end
349
+
350
+ end