fssm 0.0.8

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,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