vidibus-watch_folder 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.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 André Pankratz
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,197 @@
1
+ # Vidibus::WatchFolder [![](http://travis-ci.org/vidibus/vidibus-watch_folder.png)](http://travis-ci.org/vidibus/vidibus-watch_folder)
2
+
3
+ This gem lets you create multipe watch folders within your application, e.g. to provide individual FTP mount points for customers, maybe in combination with [Vidibus::Pureftpd](https://github.com/vidibus/vidibus-pureftpd).
4
+
5
+ To store each watch folder configuration, [Mongoid](http://mongoid.org/en/mongoid/index.html) (~> 2.5) is used. Files are processed asynchronously with [DelayedJob](https://github.com/collectiveidea/delayed_job).
6
+
7
+ This gem is part of [Vidibus](http://vidibus.org), an open source toolset for building distributed (video) applications.
8
+
9
+
10
+ ## Installation
11
+
12
+ Add `gem 'vidibus-watch_folder'` to the Gemfile of your application. Then call `bundle install` on your console.
13
+
14
+ This gem relies on [Listen](https://github.com/guard/listen) to detect changes. If you're on Windows, you'll want to install an additional file system adapter to increase performance:
15
+
16
+ ```ruby
17
+ # Windows only!
18
+ gem 'wdm', '~> 0.0.3'
19
+ ```
20
+
21
+
22
+ ## Usage
23
+
24
+ ### Models
25
+
26
+ Setting up a custom watch folder model is easy. Since it's a `Mongoid::Document`, all of the `ActiveModel` magic is at your disposal. Just add some watch folder settings:
27
+
28
+ ```ruby
29
+ class Example < Vidibus::WatchFolder::Base
30
+
31
+ # Define a root directory to store files in.
32
+ root Rails.root.join('examples')
33
+
34
+ # Define folders that should automatically be created.
35
+ folders 'in', 'out'
36
+
37
+ # Define callbacks to perform when files change.
38
+ #
39
+ # Use filter :when to define events to watch. Supported event types are:
40
+ # :added, :modified, :removed
41
+ #
42
+ # Add filter :delay to perform callback later. Execution will be delayed
43
+ # until the watched file will not have been changed for given period of time.
44
+ # This is useful for waiting until an upload is completed.
45
+ #
46
+ # Set filter :ignore to exclude file names matching given regex.
47
+ #
48
+ # Provide :folders to limit this callback to certain folders.
49
+ callback :create_upload, {
50
+ :when => :added,
51
+ :delay => 1.minute,
52
+ :folders => 'in',
53
+ :ignore => /^\.pureftpd-upload/
54
+ }
55
+ callback :destroy_upload, :when => :removed
56
+
57
+ # Callback to process created files
58
+ def create_upload(event, path)
59
+ ...
60
+ end
61
+
62
+ # Callback to handle deleted files
63
+ def destroy_upload(event, path)
64
+ ...
65
+ end
66
+ end
67
+ ```
68
+
69
+
70
+ ### Instances
71
+
72
+ Handling a watch folder instance is straightforward:
73
+
74
+ ```ruby
75
+ example = Example.create
76
+
77
+ # Access instance properties
78
+ example.uuid # => 98fe6010e7b5012f7e4c6c626d58b44c
79
+ example.path # => '/path/to/rails/examples/98fe6010e7b5012f7e4c6c626d58b44c/'
80
+ example.files # => ['<FILE_PATH>', ...]
81
+
82
+ # Destroy the instance (will remove its path, too)
83
+ example.destroy
84
+ ```
85
+
86
+
87
+ ### Listening for file changes
88
+
89
+ File changes are detected by performing `Vidibus::WatchFolder.listen`. Beware, this method is blocking, so better spawn the daemon.
90
+
91
+
92
+ #### Listener daemon
93
+
94
+ To run the listener as daemon, this gem provides a shell script. Install it with
95
+
96
+ ```
97
+ rails g vidibus:watch_folder
98
+ ```
99
+
100
+ The daemon requires that `gem 'daemons'` is installed. To spawn him, enter
101
+
102
+ ```
103
+ script/watch_folder start
104
+ ```
105
+
106
+ #### Possible caveat
107
+
108
+ To collect the paths to listen to, `Vidibus::WatchFolder.listen` requires that all classes inheriting `Vidibus::WatchFolder::Base` have been loaded.
109
+
110
+ Because Rails is autoloading almost everything in development, this requirement is not met without the help of a little hack: To trigger autoloading, the listener collects all aforementioned class names from the `app` directory and constantizes them.
111
+
112
+ **So here's the caveat:** If you define watch folder models outside of the `app` directory, you'll have to let the listener know. An initializer is perfect for that:
113
+
114
+ ```ruby
115
+ # Collect all watch folder models in lib, too
116
+ Vidibus::WatchFolder.autoload_paths << '/lib/**/*.rb'
117
+ ```
118
+
119
+
120
+ ## Deployment
121
+
122
+ A Capistrano configuration is included. Require it in your Capistrano `config.rb`.
123
+
124
+ ```ruby
125
+ require 'vidibus/watch_folder/capistrano'
126
+ ```
127
+
128
+ That will add a bunch of callback hooks.
129
+
130
+ ```ruby
131
+ after 'deploy:stop', 'vidibus:watch_folder:stop'
132
+ after 'deploy:start', 'vidibus:watch_folder:start'
133
+ after 'deploy:restart', 'vidibus:watch_folder:restart'
134
+ ```
135
+
136
+ If you need more control over the callbacks, you may load just the recipes without the hooks.
137
+
138
+ ```ruby
139
+ require 'vidibus/watch_folder/capistrano/recipes'
140
+ ```
141
+
142
+ ### Shared folders
143
+
144
+ In case you want to put files into a shared folder, you may run into a validation issue. Here's a configuration for our watch folder example that gets symlinked with a twist:
145
+
146
+ ```ruby
147
+ namespace :examples do
148
+ task :setup do
149
+ path = File.join(shared_path, 'examples')
150
+ run "mkdir -p #{path}"
151
+ run "chmod -R 777 #{path}"
152
+ end
153
+
154
+ task :symlink do
155
+ run "ln -nfs #{shared_path}/examples #{release_path}/"
156
+ end
157
+ end
158
+
159
+ after 'deploy:setup', 'examples:setup'
160
+ before 'deploy:assets:precompile', 'examples:symlink'
161
+ ```
162
+
163
+ The important thing is the last line. Instead of the usual `after 'deploy:update_code'` hook we're triggering the symlink on `before 'deploy:assets:precompile'`. The reason is that precompiling initializes the Rails app which will fail if the example directory does not exist yet.
164
+
165
+
166
+ ## Testing
167
+
168
+ To test this gem, call `bundle install` and `bundle exec rspec spec` on your console.
169
+
170
+ When testing your application you may want to define a different root path for your watch folder models. Just override them somewhere in your test files, for example in `spec_helper.rb`:
171
+
172
+ ```ruby
173
+ # Set different root for watch folder example
174
+ Example.root('spec/support/examples')
175
+ ```
176
+
177
+ Make sure that directory exists. From your Rails root call:
178
+
179
+ ```
180
+ mkdir spec/support/examples
181
+ touch spec/support/examples/.gitkeep
182
+ ```
183
+
184
+ To clean up the test folders, add the following to your RSpec config:
185
+
186
+ ```ruby
187
+ RSpec.configure do |config|
188
+ config.before(:each) do
189
+ FileUtils.rm_r(Dir['spec/support/examples/*'].reject {|e| e == '.gitkeep'})
190
+ end
191
+ end
192
+ ```
193
+
194
+
195
+ ## Copyright
196
+
197
+ &copy; 2012 André Pankratz. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ $:.unshift File.expand_path('../lib/', __FILE__)
2
+
3
+ require 'bundler'
4
+ require 'rdoc/task'
5
+ require 'rspec'
6
+ require 'rspec/core/rake_task'
7
+ require 'vidibus/watch_folder/version'
8
+
9
+ Bundler::GemHelper.install_tasks
10
+
11
+ Rake::RDocTask.new do |rdoc|
12
+ rdoc.rdoc_dir = 'rdoc'
13
+ rdoc.title = "vidibus-sysinfo #{Vidibus::WatchFolder::VERSION}"
14
+ rdoc.rdoc_files.include('README*')
15
+ rdoc.rdoc_files.include('lib/**/*.rb')
16
+ rdoc.options << '--charset=utf-8'
17
+ end
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path('../../config/environment', __FILE__)
4
+ require 'vidibus/watch_folder/daemon'
5
+
6
+ Vidibus::WatchFolder.autoload_paths << Rails.root.join('app/**/*.rb')
7
+ Vidibus::WatchFolder.path_mapping << [Rails.root.to_s, '.+']
8
+ Vidibus::WatchFolder::Daemon.new(ARGV).daemonize
@@ -0,0 +1,14 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/named_base'
3
+
4
+ module Vidibus
5
+ class WatchFolderGenerator < Rails::Generators::Base
6
+
7
+ self.source_paths << File.join(File.dirname(__FILE__), 'templates')
8
+
9
+ def create_script_file
10
+ template 'script', 'script/watch_folder'
11
+ chmod 'script/watch_folder', 0755
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,197 @@
1
+ require 'mongoid'
2
+ require 'digest'
3
+ require 'vidibus-uuid'
4
+
5
+ module Vidibus
6
+ module WatchFolder
7
+ class Base
8
+ include Mongoid::Document
9
+ include Vidibus::Uuid::Mongoid
10
+
11
+ class ConfigError < Error; end
12
+
13
+ after_create :setup
14
+ after_destroy :teardown
15
+
16
+ # Return the configured root path
17
+ def root
18
+ self.class.config[:root] || raise(ConfigError, 'No root configured')
19
+ end
20
+
21
+ # Return the absolute path to this watch folder.
22
+ def path
23
+ File.join(root, uuid) if uuid
24
+ end
25
+
26
+ # Return a list of file paths within this watch folder.
27
+ def files
28
+ Dir["#{path}/**/*"].reject do |entry|
29
+ File.directory?(entry)
30
+ end
31
+ end
32
+
33
+ # Handle event for given file path.
34
+ # Unless a checksum is provided, a asynchronous job will be started.
35
+ # If provided checksum matches the current one (or if execution
36
+ # shall not be delayed), appropriate callbacks will be performed.
37
+ def handle(event, file_path, last_checksum = nil)
38
+ return unless File.exist?(file_path) && !File.directory?(file_path)
39
+ callbacks = self.class.config[:callback]
40
+ callbacks.each do |folder, handlers|
41
+ unless folder == :any
42
+ pattern = %r(^#{path}/#{folder}/.+$)
43
+ next unless file_path[pattern]
44
+ end
45
+ matching = handlers.select { |c| c[:when].include?(event) }
46
+ matching.each do |handler|
47
+ next if handler[:ignore] && file_path.match(handler[:ignore])
48
+ checksum ||= Vidibus::WatchFolder.checksum(file_path)
49
+ delay = handler[:delay]
50
+ if checksum == last_checksum || (last_checksum && !delay)
51
+ send(handler[:method], event, file_path)
52
+ else
53
+ Job.create(uuid, event, file_path, checksum, delay)
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ class << self
60
+
61
+ # Set root path of this kind of watch folder.
62
+ def root(path)
63
+ path = File.expand_path(path)
64
+ unless Util::Directory.valid?(path)
65
+ raise ConfigError, "Given root '#{path}' must be a read and writable folder"
66
+ end
67
+ unless Vidibus::WatchFolder.roots.include?(path)
68
+ Vidibus::WatchFolder.roots << path
69
+ end
70
+ config[:root] = path
71
+ end
72
+
73
+ # Define folders to create automatically when an instance of this
74
+ # kind of watch folder is created.
75
+ def folders(*args)
76
+ raise ConfigError, 'Define folders' unless args.any?
77
+ config[:folders] = string_list(args)
78
+ end
79
+
80
+ # Define callbacks to perform when files change.
81
+ #
82
+ # Add filter :when to define events to watch. Supported event types
83
+ # are :added, :modified, an :removed
84
+ #
85
+ # Add filter :delay to perform callback later. Execution will then be
86
+ # delayed until the watched file will not have been changed for given
87
+ # period of time. This is useful for waiting until an upload is
88
+ # completed. If no delay has been configured, execution will be
89
+ # asynchronous nonetheless.
90
+ #
91
+ # Set filter :ignore to exclude file names matching given regex.
92
+ #
93
+ # Provide :folders to limit this callback to certain folders.
94
+ def callback(method, options = {})
95
+ config[:callback] ||= {}
96
+ opts = {:method => method}
97
+ if events = events_options(options)
98
+ opts[:when] = events
99
+ end
100
+ if delay = delay_options(options)
101
+ opts[:delay] = delay
102
+ end
103
+ if ignore = ignore_options(options)
104
+ opts[:ignore] = ignore
105
+ end
106
+ folders_options(options).each do |folder|
107
+ config[:callback][folder] ||= []
108
+ config[:callback][folder] << opts
109
+ end
110
+ end
111
+
112
+ # Inheritable getter for config.
113
+ def config
114
+ @config ||= {}
115
+ end
116
+
117
+ # Inheritable setter for config.
118
+ def config=(value)
119
+ @config = value
120
+ end
121
+
122
+ # Find an instance of this kind of watch folder by its UUID.
123
+ # Will raise an exception if no instance can be found.
124
+ def find_by_uuid(uuid)
125
+ found = where(:uuid => uuid).first || begin
126
+ raise(Mongoid::Errors::DocumentNotFound.new(self, :uuid => uuid))
127
+ end
128
+ end
129
+
130
+ private
131
+
132
+ def string_list(input)
133
+ Array(input).map { |i| i.to_s }
134
+ end
135
+
136
+ def folders_options(options)
137
+ list = string_list(options.delete(:folders))
138
+ list = [:any] unless list.any?
139
+ list
140
+ end
141
+
142
+ def events_options(options)
143
+ return unless events = string_list(options.delete(:when))
144
+ if events.any?
145
+ if (events-EVENTS).any?
146
+ raise ConfigError, "Only these events are supported: #{EVENTS}"
147
+ end
148
+ return events
149
+ end
150
+ nil
151
+ end
152
+
153
+ def delay_options(options)
154
+ return unless delay = options.delete(:delay)
155
+ unless delay.is_a?(Integer) && delay > 0
156
+ raise ConfigError, 'Delay must be defined in seconds'
157
+ end
158
+ delay
159
+ end
160
+
161
+ def ignore_options(options)
162
+ return unless ignore = options.delete(:ignore)
163
+ unless ignore.is_a?(Regexp)
164
+ raise ConfigError, 'Ignore pattern must be a regular expression'
165
+ end
166
+ ignore
167
+ end
168
+ end
169
+
170
+ private
171
+
172
+ def setup
173
+ setup_path
174
+ setup_folders
175
+ end
176
+
177
+ def setup_path
178
+ FileUtils.mkdir_p(path)
179
+ end
180
+
181
+ def setup_folders
182
+ folders = self.class.config[:folders]
183
+ return unless folders
184
+ folders.each do |folder|
185
+ FileUtils.mkdir_p(File.join(path, folder))
186
+ end
187
+ end
188
+
189
+ def teardown
190
+ unless path.to_s.length > 5
191
+ raise ConfigError, "#{path} is too short! Exiting for security reasons."
192
+ end
193
+ FileUtils.rm_r(path) if File.exist?(path)
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,40 @@
1
+ # Capistrano Recipes for watching folders.
2
+ #
3
+ # Load this file from your Capistrano config.rb:
4
+ # require 'vidibus/watch_folder/capistrano/recipes'
5
+ #
6
+ # Add these callbacks to have the watch_folder process restart when the server
7
+ # is restarted:
8
+ #
9
+ # after 'deploy:stop', 'vidibus:watch_folder:stop'
10
+ # after 'deploy:start', 'vidibus:watch_folder:start'
11
+ # after 'deploy:restart', 'vidibus:watch_folder:restart'
12
+ #
13
+ Capistrano::Configuration.instance.load do
14
+ namespace :vidibus do
15
+ namespace :watch_folder do
16
+ def rails_env
17
+ fetch(:rails_env, false) ? "RAILS_ENV=#{fetch(:rails_env)}" : ''
18
+ end
19
+
20
+ def roles
21
+ fetch(:delayed_job_server_role, :app)
22
+ end
23
+
24
+ desc 'Stop the watch_folder process'
25
+ task :stop, :roles => lambda { roles } do
26
+ run "cd #{current_path};#{rails_env} script/watch_folder stop"
27
+ end
28
+
29
+ desc 'Start the watch_folder process'
30
+ task :start, :roles => lambda { roles } do
31
+ run "cd #{current_path};#{rails_env} script/watch_folder start"
32
+ end
33
+
34
+ desc 'Restart the watch_folder process'
35
+ task :restart, :roles => lambda { roles } do
36
+ run "cd #{current_path};#{rails_env} script/watch_folder restart"
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,12 @@
1
+ require 'vidibus/watch_folder/capistrano/recipes'
2
+
3
+ # Run Capistrano Recipes for watching folders.
4
+ #
5
+ # Load this file from your Capistrano config.rb:
6
+ # require 'vidibus/watch_folder/capistrano'
7
+ #
8
+ Capistrano::Configuration.instance.load do
9
+ after 'deploy:stop', 'vidibus:watch_folder:stop'
10
+ after 'deploy:start', 'vidibus:watch_folder:start'
11
+ after 'deploy:restart', 'vidibus:watch_folder:restart'
12
+ end
@@ -0,0 +1,46 @@
1
+ begin
2
+ require 'daemons'
3
+ rescue LoadError
4
+ raise %(Please add `gem 'daemons' gem to your Gemfile for this to work)
5
+ end
6
+ require 'optparse'
7
+
8
+ module Vidibus
9
+ module WatchFolder
10
+ class Daemon
11
+
12
+ def initialize(args)
13
+ @options = {:pid_dir => "#{Rails.root}/tmp/pids"}
14
+ options = OptionParser.new do |options|
15
+ options.banner = "Usage: #{File.basename($0)} start|stop|restart"
16
+ options.on('-h', '--help', 'Show this message') do
17
+ puts options
18
+ exit 1
19
+ end
20
+ end
21
+ @args = options.parse!(args)
22
+ end
23
+
24
+ def daemonize
25
+ dir = @options[:pid_dir]
26
+ Dir.mkdir(dir) unless File.exists?(dir)
27
+ run_process('watch_folder', dir)
28
+ end
29
+
30
+ def run_process(name, dir)
31
+ Daemons.run_proc(name, :dir => dir, :dir_mode => :normal) { run }
32
+ end
33
+
34
+ def run
35
+ Dir.chdir(Rails.root)
36
+ log = File.join(Rails.root, 'log', 'watch_folder.log')
37
+ Vidibus::WatchFolder.logger = ActiveSupport::BufferedLogger.new(log)
38
+ Vidibus::WatchFolder.listen
39
+ rescue => e
40
+ Vidibus::WatchFolder.logger.fatal(e)
41
+ STDERR.puts(e.message)
42
+ exit 1
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,39 @@
1
+ require 'delayed_job_mongoid'
2
+
3
+ module Vidibus
4
+ module WatchFolder
5
+ class Job < Struct.new(:uuid, :event, :path, :checksum, :delay)
6
+ def enqueue!
7
+ validate!
8
+ args = [self]
9
+ i = delay.to_i
10
+ if i > 0
11
+ args << {:run_at => Time.now+i}
12
+ end
13
+ Delayed::Job.enqueue(*args).id
14
+ end
15
+
16
+ def perform
17
+ begin
18
+ watch_folder.handle(event, path, checksum)
19
+ rescue Mongoid::Errors::DocumentNotFound
20
+ end
21
+ end
22
+
23
+ def validate!
24
+ return if uuid && event && path && checksum
25
+ raise ArgumentError, 'Provide UUID, event, path, checksum, and an optional delay'
26
+ end
27
+
28
+ def self.create(*args)
29
+ new(*args).enqueue!
30
+ end
31
+
32
+ private
33
+
34
+ def watch_folder
35
+ Base.find_by_uuid(uuid)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,7 @@
1
+ require 'rails'
2
+
3
+ module Vidibus
4
+ module WatchFolder
5
+ class Railtie < Rails::Railtie; end
6
+ end
7
+ end
@@ -0,0 +1,17 @@
1
+ module Vidibus
2
+ module WatchFolder
3
+ module Util
4
+ module Directory
5
+ extend self
6
+
7
+ # Check if path is a read- and writable directory.
8
+ def valid?(path)
9
+ File.exist?(path) &&
10
+ File.directory?(path) &&
11
+ File.readable?(path) &&
12
+ File.writable?(path)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1 @@
1
+ require 'vidibus/watch_folder/util/directory'
@@ -0,0 +1,5 @@
1
+ module Vidibus
2
+ module WatchFolder
3
+ VERSION = '0.1.0'
4
+ end
5
+ end
@@ -0,0 +1,84 @@
1
+ require 'vidibus/watch_folder/util'
2
+ require 'vidibus/watch_folder/base'
3
+ require 'vidibus/watch_folder/job'
4
+ require 'vidibus/watch_folder/railtie' if defined?(Rails::Railtie)
5
+
6
+ require 'listen'
7
+
8
+ module Vidibus
9
+ module WatchFolder
10
+ extend self
11
+
12
+ class Error < StandardError; end
13
+ class NoRootsError < Error; end
14
+
15
+ EVENTS = %w[added modified removed]
16
+
17
+ attr_accessor :roots, :logger, :autoload_paths, :path_mapping
18
+ @roots = []
19
+ @logger = Logger.new(STDOUT)
20
+ @autoload_paths = []
21
+ @path_mapping = []
22
+
23
+ # Calculate checksum of given file path
24
+ def checksum(path)
25
+ Digest::SHA2.file(path).hexdigest
26
+ end
27
+
28
+ # Listen for changes within all roots
29
+ def listen
30
+ autoload
31
+ unless roots.any?
32
+ raise NoRootsError, 'No folders to watch!'
33
+ end
34
+ roots.uniq!
35
+ logger.debug("[#{Time.now.utc}] - Listening to #{roots.join(',')}")
36
+ args = roots + [{:latency => 0.1}]
37
+ Listen.to(*args) do |modified, added, removed|
38
+ EVENTS.each do |event|
39
+ eval(event).each do |path|
40
+ logger.debug %([#{Time.now.utc}] - #{event}: #{path})
41
+ begin
42
+ uuid = path[/^#{roots_regex}\/([^\/]+)\/.+$/, 1] || next
43
+ begin
44
+ base = Base.find_by_uuid(uuid)
45
+ base.handle(event, path)
46
+ rescue Mongoid::Errors::DocumentNotFound
47
+ logger.error %([#{Time.now.utc}] - Can't find Vidibus::WatchFolder::Base #{uuid})
48
+ end
49
+ rescue => e
50
+ logger.error("[#{Time.now.utc}] - ERROR in Vidibus::WatchFolder.listen:\n#{e.inspect}\n---\n#{e.backtrace.join("\n")}")
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ # Constantize all watch folder class names to trigger autoloading.
58
+ def autoload
59
+ return unless autoload_paths.any?
60
+ list = Dir[*autoload_paths].map do |f|
61
+ File.read(f)[/class ([^<]+) < Vidibus::WatchFolder::Base/, 1]
62
+ end.compact.map { |k| k.constantize }
63
+ end
64
+
65
+ private
66
+
67
+ # Return regular expression for root paths.
68
+ #
69
+ # If any path_mapping has been defined, that mapping will be applied.
70
+ # That is often required to turn absolute path into relative ones in order
71
+ # to avoid problems with symlinks, because uploaded files will usually go
72
+ # into a shared directory but the root paths Rails reports are from within
73
+ # the current release directory.
74
+ def roots_regex
75
+ @roots_regex ||= begin
76
+ _roots = roots.join('|')
77
+ path_mapping.each do |from, to|
78
+ _roots.gsub!(from, to)
79
+ end
80
+ /(?:#{_roots})/
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1 @@
1
+ require 'vidibus/watch_folder'
metadata ADDED
@@ -0,0 +1,256 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vidibus-watch_folder
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - André Pankratz
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-28 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mongoid
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.5'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '2.5'
30
+ - !ruby/object:Gem::Dependency
31
+ name: listen
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '0.5'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '0.5'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rb-fsevent
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.9.1
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.9.1
62
+ - !ruby/object:Gem::Dependency
63
+ name: rb-inotify
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 0.8.8
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 0.8.8
78
+ - !ruby/object:Gem::Dependency
79
+ name: vidibus-uuid
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: delayed_job_mongoid
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: bundler
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: 1.0.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: 1.0.0
126
+ - !ruby/object:Gem::Dependency
127
+ name: rake
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ - !ruby/object:Gem::Dependency
143
+ name: rdoc
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ - !ruby/object:Gem::Dependency
159
+ name: simplecov
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ - !ruby/object:Gem::Dependency
175
+ name: rspec
176
+ requirement: !ruby/object:Gem::Requirement
177
+ none: false
178
+ requirements:
179
+ - - ! '>='
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ type: :development
183
+ prerelease: false
184
+ version_requirements: !ruby/object:Gem::Requirement
185
+ none: false
186
+ requirements:
187
+ - - ! '>='
188
+ - !ruby/object:Gem::Version
189
+ version: '0'
190
+ - !ruby/object:Gem::Dependency
191
+ name: rr
192
+ requirement: !ruby/object:Gem::Requirement
193
+ none: false
194
+ requirements:
195
+ - - ! '>='
196
+ - !ruby/object:Gem::Version
197
+ version: '0'
198
+ type: :development
199
+ prerelease: false
200
+ version_requirements: !ruby/object:Gem::Requirement
201
+ none: false
202
+ requirements:
203
+ - - ! '>='
204
+ - !ruby/object:Gem::Version
205
+ version: '0'
206
+ description: Create multiple watch folders within your application, e.g. to provide
207
+ individual FTP mount points for customers.
208
+ email: andre@vidibus.com
209
+ executables: []
210
+ extensions: []
211
+ extra_rdoc_files: []
212
+ files:
213
+ - lib/generators/vidibus/templates/script
214
+ - lib/generators/vidibus/watch_folder_generator.rb
215
+ - lib/vidibus/watch_folder/base.rb
216
+ - lib/vidibus/watch_folder/capistrano/recipes.rb
217
+ - lib/vidibus/watch_folder/capistrano.rb
218
+ - lib/vidibus/watch_folder/daemon.rb
219
+ - lib/vidibus/watch_folder/job.rb
220
+ - lib/vidibus/watch_folder/railtie.rb
221
+ - lib/vidibus/watch_folder/util/directory.rb
222
+ - lib/vidibus/watch_folder/util.rb
223
+ - lib/vidibus/watch_folder/version.rb
224
+ - lib/vidibus/watch_folder.rb
225
+ - lib/vidibus-watch_folder.rb
226
+ - LICENSE
227
+ - README.md
228
+ - Rakefile
229
+ homepage: https://github.com/vidibus/vidibus-watch_folder
230
+ licenses: []
231
+ post_install_message:
232
+ rdoc_options: []
233
+ require_paths:
234
+ - lib
235
+ required_ruby_version: !ruby/object:Gem::Requirement
236
+ none: false
237
+ requirements:
238
+ - - ! '>='
239
+ - !ruby/object:Gem::Version
240
+ version: '0'
241
+ segments:
242
+ - 0
243
+ hash: -1021260411944907488
244
+ required_rubygems_version: !ruby/object:Gem::Requirement
245
+ none: false
246
+ requirements:
247
+ - - ! '>='
248
+ - !ruby/object:Gem::Version
249
+ version: 1.3.6
250
+ requirements: []
251
+ rubyforge_project: vidibus-watch_folder
252
+ rubygems_version: 1.8.24
253
+ signing_key:
254
+ specification_version: 3
255
+ summary: Watch folders based on Mongoid with asynchronous processing
256
+ test_files: []