file-watcher 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/watch_config.rb +34 -0
- data/watch_job.rb +47 -0
- data/watcher.rb +90 -0
- metadata +79 -0
data/watch_config.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module WatchConfig
|
2
|
+
|
3
|
+
def self.included base
|
4
|
+
base.extend( ClassMethods)
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def validate_new_job wj
|
9
|
+
raise "Error: Watch job is missing watch dir: #{wj.inspect}" unless wj.watch_criteria.keys.include? :target_dir
|
10
|
+
|
11
|
+
raise "Error: Watch directory doesn't exist: #{wj.watch_criteria[:target_dir]}" unless File.exist? wj.watch_criteria[:target_dir]
|
12
|
+
|
13
|
+
raise "Error: Watch configuration did not specify any events to watch for (#{wj.inspect})" if wj.watch_criteria[:events].empty?
|
14
|
+
|
15
|
+
|
16
|
+
raise "Error: Only http watch actions are supported: #{wj}" unless wj.watch_action.keys == [:http]
|
17
|
+
|
18
|
+
raise "Error: Invalid/Unsupported http method [#{wj.watch_action[:http][:method]}] in config [#{wj.watch_action.inspect}]" unless wj.watch_action[:http][:method] == :post
|
19
|
+
end
|
20
|
+
|
21
|
+
def new_watch_job &block
|
22
|
+
wj = WatchJob.new
|
23
|
+
|
24
|
+
yield wj
|
25
|
+
|
26
|
+
validate_new_job wj
|
27
|
+
self.registered_jobs << wj
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
|
data/watch_job.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.join( File.dirname(__FILE__), 'watch_config')
|
2
|
+
require 'cgi'
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
class WatchJob
|
7
|
+
include WatchConfig
|
8
|
+
attr_accessor :watch_criteria, :watch_action
|
9
|
+
|
10
|
+
@@registered_jobs = []
|
11
|
+
|
12
|
+
def self.registered_jobs
|
13
|
+
@@registered_jobs
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def do_post event
|
18
|
+
Net::HTTP.start(watch_action[:http][:hostname]) do |http|
|
19
|
+
if watch_action[:http][:ssl]
|
20
|
+
protocol = 'https'
|
21
|
+
else
|
22
|
+
protocol = 'http'
|
23
|
+
end
|
24
|
+
|
25
|
+
url = "#{protocol}://#{watch_action[:http][:auth_user]}:#{watch_action[:http][:auth_pass]}@#{watch_action[:http][:hostname]}:#{watch_action[:http][:port]}#{watch_action[:http][:command_uri]}"
|
26
|
+
|
27
|
+
|
28
|
+
body = watch_action[:http][:command].merge({ :args => watch_action[:http][:command][:args].dup.push(event.name) } )
|
29
|
+
|
30
|
+
puts "URL: #{url}"
|
31
|
+
puts "body: #{body}"
|
32
|
+
|
33
|
+
res = Net::HTTP.post_form(URI.parse(url), {'body' => body.to_json } )
|
34
|
+
puts "Response: #{res}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def event_handler event
|
39
|
+
debugger
|
40
|
+
return unless event.name =~ watch_criteria[:file_glob]
|
41
|
+
|
42
|
+
if watch_action.keys.first == :http && watch_action[:http][:method] == :post
|
43
|
+
do_post event
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
data/watcher.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'ruby-debug'
|
4
|
+
require 'base_app'
|
5
|
+
require 'rb-inotify'
|
6
|
+
require 'json'
|
7
|
+
require File.join( File.dirname(__FILE__), 'watch_job' )
|
8
|
+
|
9
|
+
|
10
|
+
#
|
11
|
+
# to watch the current directory, run:
|
12
|
+
#
|
13
|
+
# ruby watcher.rb -d . -c trigger
|
14
|
+
#
|
15
|
+
# This also specifies a 'command' directory - a place where if you
|
16
|
+
# touch a 'stop' file, the inotify loop will terminate.
|
17
|
+
#
|
18
|
+
|
19
|
+
|
20
|
+
class Watcher < BaseApp
|
21
|
+
|
22
|
+
def command_line_arguments
|
23
|
+
super.concat [["w","watch-job-dir=","Directory of watch jobs.", true],
|
24
|
+
["c","control-dir=","Control directory to watch for a 'stop' file..", true]]
|
25
|
+
end
|
26
|
+
|
27
|
+
def make_flags_map flags
|
28
|
+
flags.inject({}) do |m,f|
|
29
|
+
m[f] = true
|
30
|
+
m
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def stop_file_path
|
35
|
+
"#{@control_dir}/stop"
|
36
|
+
end
|
37
|
+
|
38
|
+
def handle_event event, flags
|
39
|
+
if event.name == 'stop'
|
40
|
+
if File.exist?(stop_file_path)
|
41
|
+
@notifier.stop
|
42
|
+
File.delete stop_file_path
|
43
|
+
return
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# we don't care about things like 'ls' or other changes on the directory itself
|
48
|
+
return if flags[:isdir]
|
49
|
+
|
50
|
+
puts "handle event: #{event.name} was #{flags.inspect}"
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
def run
|
56
|
+
@control_dir = self.control_dir || '.'
|
57
|
+
|
58
|
+
|
59
|
+
Dir["#{@watch_job_dir}/*.rb"].each do |f|
|
60
|
+
require File.join( File.dirname(__FILE__), f)
|
61
|
+
end
|
62
|
+
|
63
|
+
@notifier = INotify::Notifier.new
|
64
|
+
# these are all the events we can watch for: :access, :attrib,
|
65
|
+
# :close_write, :close_nowrite, :create, :delete, :delete_self,
|
66
|
+
# :modify, :move_self, :moved_from, :moved_to, :open
|
67
|
+
|
68
|
+
# :access is too noisy for watching a directory (lots and lots of events)
|
69
|
+
# notifier.watch(@dir, :attrib, :close_write, :close_nowrite, :create, :delete, :delete_self, :modify, :move_self, :moved_from, :moved_to, :open) do |event|
|
70
|
+
|
71
|
+
WatchJob.registered_jobs.each do |job|
|
72
|
+
@notifier.watch(job.watch_criteria[:target_dir], *job.watch_criteria[:events]) do |event|
|
73
|
+
job.event_handler event
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
@notifier.watch(@control_dir, :close_write, :close_nowrite, :create, :delete, :modify, :moved_from, :moved_to, :delete_self, :move_self, :recursive) do |event|
|
78
|
+
puts "CONTROL DIR HIT: #{@control_dir}"
|
79
|
+
handle_event event, make_flags_map(event.flags)
|
80
|
+
end
|
81
|
+
|
82
|
+
puts "Entering run loop."
|
83
|
+
@notifier.run
|
84
|
+
puts "Exited run loop."
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
if $0 == __FILE__
|
89
|
+
Watcher.main
|
90
|
+
end
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: file-watcher
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
version: 1.0.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Paul Santa Clara
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-02-25 00:00:00 -05:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rb-inotify
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
- 8
|
30
|
+
- 4
|
31
|
+
version: 0.8.4
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
description: |
|
35
|
+
Use inotify to watch for file system modifcations and take a configured action.'
|
36
|
+
|
37
|
+
email: "kburton@relaynetwork.com "
|
38
|
+
executables: []
|
39
|
+
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files: []
|
43
|
+
|
44
|
+
files:
|
45
|
+
- watch_config.rb
|
46
|
+
- watcher.rb
|
47
|
+
- watch_job.rb
|
48
|
+
has_rdoc: true
|
49
|
+
homepage:
|
50
|
+
licenses: []
|
51
|
+
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options: []
|
54
|
+
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
segments:
|
62
|
+
- 0
|
63
|
+
version: "0"
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
segments:
|
69
|
+
- 0
|
70
|
+
version: "0"
|
71
|
+
requirements: []
|
72
|
+
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 1.3.6
|
75
|
+
signing_key:
|
76
|
+
specification_version: 3
|
77
|
+
summary: Use inotify to watch for file system modifcations and take a configured action.
|
78
|
+
test_files: []
|
79
|
+
|