file_monitor 0.1.0

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