file_monitor 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ vendor/**
2
+ .bundle/**
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/.rvmrc ADDED
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # This is an RVM Project .rvmrc file, used to automatically load the ruby
4
+ # development environment upon cd'ing into the directory
5
+
6
+ # First we specify our desired <ruby>[@<gemset>], the @gemset name is optional.
7
+ environment_id="ruby-1.9.2-p180@file_daemon"
8
+
9
+ #
10
+ # First we attempt to load the desired environment directly from the environment
11
+ # file. This is very fast and efficicent compared to running through the entire
12
+ # CLI and selector. If you want feedback on which environment was used then
13
+ # insert the word 'use' after --create as this triggers verbose mode.
14
+ #
15
+ if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
16
+ && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]] ; then
17
+ \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
18
+
19
+ [[ -s ".rvm/hooks/after_use" ]] && . ".rvm/hooks/after_use"
20
+ else
21
+ # If the environment file has not yet been created, use the RVM CLI to select.
22
+ rvm --create use "$environment_id"
23
+ fi
24
+
25
+ #
26
+ # If you use an RVM gemset file to install a list of gems (*.gems), you can have
27
+ # it be automatically loaded. Uncomment the following and adjust the filename if
28
+ # necessary.
29
+ #
30
+ # filename=".gems"
31
+ # if [[ -s "$filename" ]] ; then
32
+ # rvm gemset import "$filename" | grep -v already | grep -v listed | grep -v complete | sed '/^$/d'
33
+ # fi
34
+
35
+ #
36
+ # If you use bundler and would like to run bundle each time you enter the
37
+ # directory, you can uncomment the following code.
38
+ #
39
+ # # Ensure that Bundler is installed. Install it if it is not.
40
+ # if ! command -v bundle >/dev/null; then
41
+ # printf "The rubygem 'bundler' is not installed. Installing it now.\n"
42
+ # gem install bundler
43
+ # fi
44
+ #
45
+ # # Bundle while reducing excess noise.
46
+ # printf "Bundling your gems. This may take a few minutes on a fresh clone.\n"
47
+ # bundle | grep -v '^Using ' | grep -v ' is complete' | sed '/^$/d'
48
+ #
49
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,38 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ file_monitor (0.1.0)
5
+ daemons
6
+ fssm
7
+ rb-inotify
8
+ trollop
9
+
10
+ GEM
11
+ remote: http://rubygems.org/
12
+ specs:
13
+ daemons (1.1.0)
14
+ diff-lcs (1.1.2)
15
+ ffi (1.0.7)
16
+ rake (>= 0.8.7)
17
+ flexmock (0.9.0)
18
+ fssm (0.2.5)
19
+ rake (0.8.7)
20
+ rb-inotify (0.8.4)
21
+ ffi (>= 0.5.0)
22
+ rspec (2.5.0)
23
+ rspec-core (~> 2.5.0)
24
+ rspec-expectations (~> 2.5.0)
25
+ rspec-mocks (~> 2.5.0)
26
+ rspec-core (2.5.1)
27
+ rspec-expectations (2.5.0)
28
+ diff-lcs (~> 1.1.2)
29
+ rspec-mocks (2.5.0)
30
+ trollop (1.16.2)
31
+
32
+ PLATFORMS
33
+ ruby
34
+
35
+ DEPENDENCIES
36
+ file_monitor!
37
+ flexmock
38
+ rspec
@@ -0,0 +1,22 @@
1
+ # FileMonitor
2
+
3
+ ### Usage
4
+ # Given a yaml configuration file like so:
5
+ #
6
+ # logfile:
7
+ # path: /tmp/file_monitor.log
8
+ # monitor:
9
+ # path: /tmp
10
+
11
+ # Run from shell
12
+ file_monitor --config-path /tmp/config.yml start
13
+
14
+ # You will now see create,updates, & deletes from /tmp printed to STDOUT
15
+
16
+
17
+
18
+ #### TODO
19
+ - daemon plugin so the file monitoring doesn't block the shell
20
+
21
+
22
+
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../lib/file_monitor', __FILE__)
3
+ FileMonitor::CommandLine.new ARGV
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib/', __FILE__)
3
+ $:.unshift lib unless $:.include?(lib)
4
+
5
+ require 'file_monitor/version'
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "file_monitor"
9
+ s.version = FileMonitor::VERSION
10
+ s.platform = Gem::Platform::RUBY
11
+ s.authors = ["James Cook", "Ben Holley"]
12
+ s.email = ["james@isotope11.com"]
13
+ s.summary = %q{Wrapper around FSSM for ease of use"}
14
+ #s.description = %q{}
15
+
16
+ s.required_rubygems_version = ">= 1.3.6"
17
+ s.rubyforge_project = "file_monitor"
18
+
19
+ s.add_dependency "rb-inotify"
20
+ s.add_dependency "daemons"
21
+ s.add_dependency "fssm"
22
+ s.add_dependency "trollop"
23
+ s.add_development_dependency "rspec"
24
+ s.add_development_dependency "flexmock"
25
+
26
+ s.files = `git ls-files`.split("\n")
27
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
28
+ s.executables = %w(file_monitor)
29
+ s.default_executable = "file_monitor"
30
+ s.require_paths = ["lib"]
31
+ end
@@ -0,0 +1,21 @@
1
+ require 'bundler/setup'
2
+
3
+ # Standard libraries
4
+ require 'logger'
5
+ require 'yaml'
6
+
7
+ # Gem libraries
8
+ require 'fssm'
9
+
10
+ lib = File.expand_path('../', __FILE__)
11
+ $:.unshift lib unless $:.include?(lib)
12
+
13
+ module FileMonitor
14
+ autoload :Version, 'file_monitor/version'
15
+ autoload :Core, 'file_monitor/core'
16
+ autoload :CommandLine, 'file_monitor/command_line'
17
+ autoload :Configuration, 'file_monitor/configuration'
18
+ autoload :Logger, 'file_monitor/logger' # This should go away.. needs to be a hook
19
+ autoload :Worker, 'file_monitor/worker'
20
+ require 'file_monitor/hooks'
21
+ end
@@ -0,0 +1,46 @@
1
+ module FileMonitor
2
+ class CommandLine
3
+ def initialize argv=[]
4
+ require 'trollop'
5
+ parse self, argv if argv.any?
6
+ end
7
+
8
+ def file_monitor_banner
9
+ <<-EOT
10
+ Usage: file_monitor -c /path/to/config.yml COMMAND [ARGS]
11
+
12
+ The file monitor commands are:
13
+ start Starts the file monitor and watches a specified directory.
14
+ stop Stops the file monitor
15
+ --version
16
+ EOT
17
+ end
18
+
19
+ def available_commands
20
+ %w(start stop)
21
+ end
22
+
23
+ def parse _self, argv
24
+ global_opts = Trollop::options(argv) do
25
+ banner _self.file_monitor_banner
26
+ opt :config_path, "Configuration Path", :short => "-c", :type => :string
27
+ stop_on _self.available_commands
28
+ end
29
+
30
+ command = argv.shift # get the subcommand
31
+ cmd_opts = case command
32
+ when "start"
33
+ Trollop::options(argv) do
34
+ opt :config_path, "Configuration Path", :short => "c"
35
+ end
36
+
37
+ watch_dir = argv.unshift
38
+ config_path = global_opts[:config_path]
39
+ FileMonitor::Core.new(:config_path => config_path, :watch_dir => File.expand_path(File.join(watch_dir))).run
40
+ when "stop"
41
+ else
42
+ Trollop::die "unknown command #{command.inspect}"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,12 @@
1
+ module FileMonitor
2
+ class Configuration
3
+ attr_accessor :logfile_path, :watch_dir
4
+ attr_reader :data
5
+ def initialize *args
6
+ options = args.last.is_a?(Hash) ? args.pop : {}
7
+ config_path = options[:config_path]
8
+ config_content = ::File.exist?(config_path.to_s) ? YAML.load_file(config_path) : {"logfile" => {}, "monitor" => {}}
9
+ @data = config_content
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,43 @@
1
+ module FileMonitor
2
+ class Core
3
+ attr_reader :hooks
4
+ attr_accessor :config
5
+ def initialize *args
6
+ args.flatten!
7
+ options = args.last.is_a?(Hash) ? args.pop : {}
8
+ @hooks = []
9
+ @config = FileMonitor::Configuration.new(:config_path => options[:config_path], :watch_dir => options[:watch_dir])
10
+ end
11
+
12
+ def add_hook klass, call_method=:run
13
+ @hooks.push [klass, call_method]
14
+ self
15
+ end
16
+
17
+ def remove_hook klass
18
+ @hooks.delete_if{|k,m| k.to_s == klass.to_s }
19
+ self
20
+ end
21
+
22
+ def run
23
+ _self = self
24
+ FSSM.monitor(config.data["monitor"]["path"]) do
25
+ update{|base, relative| _self.hook!(:update, base, relative) }
26
+ delete{|base, relative| _self.hook!(:delete, base, relative) }
27
+ create{|base, relative| _self.hook!(:create, base, relative) }
28
+ end
29
+ end
30
+
31
+ def hook! event, *args
32
+ if hooks.empty?
33
+ hooks.push default_hook
34
+ end
35
+ hooks.map{|klass, call_method| FileMonitor::Hooks.const_get(klass).send(call_method, *[event, args]) }
36
+ end
37
+
38
+ private
39
+ def default_hook
40
+ ["StandardOutput", "run"]
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,9 @@
1
+ lib = File.expand_path('../', __FILE__)
2
+ $:.unshift lib unless $:.include?(lib)
3
+
4
+ module FileMonitor
5
+ module Hooks
6
+ autoload :StandardOutput, 'hooks/standard_output.rb'
7
+ autoload :FileLog, 'hooks/file_log.rb'
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ module FileMonitor
2
+ module Hooks
3
+ class FileLog
4
+ def self.run *args
5
+ io << args.inspect
6
+ end
7
+
8
+ def self.io
9
+ require "logger"
10
+ @io = ::Logger.new(log_path)
11
+ end
12
+
13
+ def self.log_path=(path)
14
+ @log_path = path
15
+ end
16
+
17
+ def self.log_path; @log_path; end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ module FileMonitor
2
+ module Hooks
3
+ class StandardOutput
4
+ # This is the default hook. Writes CREATE, UPDATE and DELETE events to STDOUT
5
+ def self.run *args
6
+ io.puts args.inspect
7
+ end
8
+
9
+ def self.io
10
+ @io = STDOUT if @io.nil?
11
+ @io
12
+ end
13
+
14
+ def self.io= _io
15
+ @io = _io # Set to a file, StringIO, etc. StringIO is used for specs.
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ module FileMonitor
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe FileMonitor do
4
+ describe FileMonitor::Core do
5
+ before do
6
+ @monitor = FileMonitor::Core.new [{}]
7
+ end
8
+ context "#add_hook" do
9
+ it "should register a hook" do
10
+ @monitor.add_hook "Klass", :run
11
+ @monitor.hooks.last.should == ["Klass", :run]
12
+ end
13
+ end
14
+
15
+ context "#remove_hook" do
16
+ it "should unregister a hook" do
17
+ @monitor.add_hook "Klass", :run
18
+ @monitor.remove_hook "Klass"
19
+ @monitor.hooks.should be_empty
20
+ end
21
+ end
22
+
23
+ context "#hook!" do
24
+ before do
25
+ @io = StringIO.new
26
+ FileMonitor::Hooks::StandardOutput.io = @io
27
+ end
28
+
29
+ it "should fire the run method on registered hooks" do
30
+ @monitor.hook! [:update, "x", "y"] # Simulate what FSSM passes in when a file gets modified or created
31
+ @io.rewind
32
+ @io.read.should == "[[:update, \"x\", \"y\"], []]\n"
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,4 @@
1
+ logfile:
2
+ path: /tmp/file_monitor_log
3
+ monitor:
4
+ path: /tmp
@@ -0,0 +1,21 @@
1
+ require "spec_helper"
2
+
3
+ describe FileMonitor::CommandLine do
4
+ context "#parse" do
5
+ before :each do
6
+ flexmock( FileMonitor::Core).new_instances do |m|
7
+ m.should_receive(:run).once.and_return{ true }
8
+ end
9
+ end
10
+
11
+ after :each do
12
+ flexmock_verify
13
+ end
14
+
15
+ context "given a config path and a start/stop command" do
16
+ it "should call FileMonitor::Core" do
17
+ FileMonitor::CommandLine.new ["--config-path", "/tmp/config.yml", "start"]
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ require "spec_helper"
2
+ describe FileMonitor::Configuration do
3
+ context "#new" do
4
+ context "given a valid path" do
5
+ let(:config_path){ File.join(File.dirname(__FILE__), "..", "..", "fixtures", "config.yml") }
6
+ it "should parse and have convenience methods for each settings" do
7
+ @config = FileMonitor::Configuration.new :config_path => config_path
8
+ @config.data.should be_an_instance_of(Hash)
9
+ @config.data["logfile"].should be_an_instance_of(Hash)
10
+ @config.data["monitor"].should be_an_instance_of(Hash)
11
+ @config.data["logfile"]["path"].should be_an_instance_of(String)
12
+ @config.data["monitor"]["path"].should be_an_instance_of(String)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+ require 'tempfile'
3
+
4
+ describe FileMonitor do
5
+ describe FileMonitor::Hooks::FileLog do
6
+ before do
7
+ @monitor = FileMonitor::Core.new [{}]
8
+ @file = Tempfile.new "sample_file_monitor_hook"
9
+ FileMonitor::Hooks::FileLog.log_path = @file.path
10
+ @monitor.add_hook "FileLog", :run
11
+ end
12
+
13
+ context "#hook!" do
14
+
15
+ it "should fire the run method on registered hooks" do
16
+ @monitor.hook! [:update, "x", "y"]
17
+ @file.rewind
18
+ @file.read.should == "[[:update, \"x\", \"y\"], []]"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,7 @@
1
+ lib = File.expand_path('../../', __FILE__)
2
+ $:.unshift lib unless $:.include?(lib)
3
+ require "lib/file_monitor.rb"
4
+
5
+ RSpec.configure do |config|
6
+ config.mock_with :flexmock
7
+ end
metadata ADDED
@@ -0,0 +1,171 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: file_monitor
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - James Cook
13
+ - Ben Holley
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-31 00:00:00 -05:00
19
+ default_executable: file_monitor
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rb-inotify
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: daemons
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 0
44
+ version: "0"
45
+ type: :runtime
46
+ version_requirements: *id002
47
+ - !ruby/object:Gem::Dependency
48
+ name: fssm
49
+ prerelease: false
50
+ requirement: &id003 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 0
57
+ version: "0"
58
+ type: :runtime
59
+ version_requirements: *id003
60
+ - !ruby/object:Gem::Dependency
61
+ name: trollop
62
+ prerelease: false
63
+ requirement: &id004 !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ segments:
69
+ - 0
70
+ version: "0"
71
+ type: :runtime
72
+ version_requirements: *id004
73
+ - !ruby/object:Gem::Dependency
74
+ name: rspec
75
+ prerelease: false
76
+ requirement: &id005 !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ segments:
82
+ - 0
83
+ version: "0"
84
+ type: :development
85
+ version_requirements: *id005
86
+ - !ruby/object:Gem::Dependency
87
+ name: flexmock
88
+ prerelease: false
89
+ requirement: &id006 !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ segments:
95
+ - 0
96
+ version: "0"
97
+ type: :development
98
+ version_requirements: *id006
99
+ description:
100
+ email:
101
+ - james@isotope11.com
102
+ executables:
103
+ - file_monitor
104
+ extensions: []
105
+
106
+ extra_rdoc_files: []
107
+
108
+ files:
109
+ - .gitignore
110
+ - .rspec
111
+ - .rvmrc
112
+ - Gemfile
113
+ - Gemfile.lock
114
+ - README.md
115
+ - bin/file_monitor
116
+ - file_monitor.gemspec
117
+ - lib/file_monitor.rb
118
+ - lib/file_monitor/command_line.rb
119
+ - lib/file_monitor/configuration.rb
120
+ - lib/file_monitor/core.rb
121
+ - lib/file_monitor/hooks.rb
122
+ - lib/file_monitor/hooks/file_log.rb
123
+ - lib/file_monitor/hooks/standard_output.rb
124
+ - lib/file_monitor/version.rb
125
+ - spec/file_daemon_spec.rb
126
+ - spec/fixtures/config.yml
127
+ - spec/lib/file_monitor/command_line_spec.rb
128
+ - spec/lib/file_monitor/configuration_spec.rb
129
+ - spec/lib/file_monitor/file_log_hook_spec.rb
130
+ - spec/spec_helper.rb
131
+ has_rdoc: true
132
+ homepage:
133
+ licenses: []
134
+
135
+ post_install_message:
136
+ rdoc_options: []
137
+
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ none: false
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ segments:
146
+ - 0
147
+ version: "0"
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
149
+ none: false
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ segments:
154
+ - 1
155
+ - 3
156
+ - 6
157
+ version: 1.3.6
158
+ requirements: []
159
+
160
+ rubyforge_project: file_monitor
161
+ rubygems_version: 1.3.7
162
+ signing_key:
163
+ specification_version: 3
164
+ summary: Wrapper around FSSM for ease of use"
165
+ test_files:
166
+ - spec/file_daemon_spec.rb
167
+ - spec/fixtures/config.yml
168
+ - spec/lib/file_monitor/command_line_spec.rb
169
+ - spec/lib/file_monitor/configuration_spec.rb
170
+ - spec/lib/file_monitor/file_log_hook_spec.rb
171
+ - spec/spec_helper.rb