rivendell-import 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +21 -0
- data/Gemfile +11 -0
- data/Guardfile +14 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +4 -0
- data/bin/rivendell-import +6 -0
- data/db/migrate/20120920712200_create_tasks.rb +21 -0
- data/db/migrate/20120927194300_create_notifiers.rb +14 -0
- data/db/migrate/20120927203600_create_notifications.rb +14 -0
- data/examples/.gitignore +2 -0
- data/examples/config.rb +31 -0
- data/features/manage_cart_attributes.feature +20 -0
- data/features/manage_file_matching.feature +44 -0
- data/features/step_definitions/import_steps.rb +38 -0
- data/features/support/env.rb +19 -0
- data/features/support/mock_xport.rb +34 -0
- data/lib/rivendell/import.rb +48 -0
- data/lib/rivendell/import/base.rb +57 -0
- data/lib/rivendell/import/cart.rb +67 -0
- data/lib/rivendell/import/carts_cache.rb +58 -0
- data/lib/rivendell/import/cli.rb +90 -0
- data/lib/rivendell/import/config.rb +13 -0
- data/lib/rivendell/import/context.rb +28 -0
- data/lib/rivendell/import/cut.rb +33 -0
- data/lib/rivendell/import/file.rb +57 -0
- data/lib/rivendell/import/notification.rb +16 -0
- data/lib/rivendell/import/notifier/base.rb +89 -0
- data/lib/rivendell/import/notifier/mail-body.erb +8 -0
- data/lib/rivendell/import/notifier/mail-subject.erb +11 -0
- data/lib/rivendell/import/notifier/mail.rb +104 -0
- data/lib/rivendell/import/notifiers.rb +24 -0
- data/lib/rivendell/import/task.rb +80 -0
- data/lib/rivendell/import/tasking/cart.rb +25 -0
- data/lib/rivendell/import/tasking/destination.rb +28 -0
- data/lib/rivendell/import/tasking/file.rb +20 -0
- data/lib/rivendell/import/tasking/status.rb +29 -0
- data/lib/rivendell/import/tasking/tags.rb +27 -0
- data/lib/rivendell/import/tasks.rb +23 -0
- data/lib/rivendell/import/version.rb +5 -0
- data/lib/rivendell/import/worker.rb +34 -0
- data/rivendell-import.gemspec +37 -0
- data/spec/fixtures/mail-body.erb +5 -0
- data/spec/rivendell/import/base_spec.rb +125 -0
- data/spec/rivendell/import/cart_spec.rb +132 -0
- data/spec/rivendell/import/carts_cache_spec.rb +110 -0
- data/spec/rivendell/import/cli_spec.rb +149 -0
- data/spec/rivendell/import/config_spec.rb +16 -0
- data/spec/rivendell/import/context_spec.rb +19 -0
- data/spec/rivendell/import/file_spec.rb +63 -0
- data/spec/rivendell/import/notifier/base_spec.rb +63 -0
- data/spec/rivendell/import/notifier/mail_spec.rb +110 -0
- data/spec/rivendell/import/task_spec.rb +217 -0
- data/spec/rivendell/import/tasks_spec.rb +30 -0
- data/spec/rivendell/import/worker_spec.rb +25 -0
- data/spec/rivendell/import_spec.rb +32 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/database_cleaner.rb +17 -0
- data/spec/support/fixtures.rb +3 -0
- data/spec/support/mail.rb +3 -0
- data/spec/support/test_notifier.rb +15 -0
- data/tasks/ci.rake +2 -0
- data/tasks/cucumber.rake +4 -0
- data/tasks/database.rake +11 -0
- data/tasks/rdoc.rake +16 -0
- data/tasks/rspec.rake +2 -0
- metadata +399 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'rspec', :version => 2 do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
end
|
9
|
+
|
10
|
+
guard 'cucumber' do
|
11
|
+
watch(%r{^features/.+\.feature$})
|
12
|
+
watch(%r{^features/support/.+$}) { 'features' }
|
13
|
+
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
|
14
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Alban Peignier
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Rivendell::Import
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'rivendell-import'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install rivendell-import
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
class CreateTasks < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :tasks do |t|
|
4
|
+
t.string :status
|
5
|
+
|
6
|
+
t.string :file_name
|
7
|
+
t.string :file_path
|
8
|
+
t.string :destination
|
9
|
+
t.string :tags
|
10
|
+
t.text :cart
|
11
|
+
|
12
|
+
t.integer :priority
|
13
|
+
|
14
|
+
t.timestamps
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.down
|
19
|
+
drop_table :tasks
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateNotifications < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :notifications do |t|
|
4
|
+
t.belongs_to :task
|
5
|
+
t.belongs_to :notifier
|
6
|
+
t.time :sent_at
|
7
|
+
t.timestamps
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.down
|
12
|
+
drop_table :notifications
|
13
|
+
end
|
14
|
+
end
|
data/examples/.gitignore
ADDED
data/examples/config.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Mail.defaults do
|
2
|
+
# delivery_method :smtp, { :address => "smtp.me.com",
|
3
|
+
# :port => 587,
|
4
|
+
# :domain => 'your.host.name',
|
5
|
+
# :user_name => '<username>',
|
6
|
+
# :password => '<password>',
|
7
|
+
# :authentication => 'plain',
|
8
|
+
# :enable_starttls_auto => true }
|
9
|
+
# end
|
10
|
+
|
11
|
+
Mail.defaults do
|
12
|
+
delivery_method :smtp, { :address => "smtp.free.fr" }
|
13
|
+
end
|
14
|
+
|
15
|
+
Rivendell::Import::Notifier::Mail.from = "root@tryphon.eu"
|
16
|
+
|
17
|
+
Rivendell::Import.config do |config|
|
18
|
+
config.to_prepare do |file|
|
19
|
+
file.in("music") do
|
20
|
+
cart.group = "MUSIC"
|
21
|
+
end
|
22
|
+
|
23
|
+
file.in("pad") do
|
24
|
+
cart.find_by_title file.basename
|
25
|
+
end
|
26
|
+
|
27
|
+
cart.group ||= "TEST"
|
28
|
+
|
29
|
+
notify 'alban@tryphon.eu', :by => :email
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
Feature: Manage Cart attributes
|
2
|
+
In order to make the correct import
|
3
|
+
An user
|
4
|
+
wants to manage carts attributes according importing file
|
5
|
+
|
6
|
+
Scenario: Seletec the cart group
|
7
|
+
Given a configuration with this prepare block
|
8
|
+
"""
|
9
|
+
cart.group = 'MUSIC'
|
10
|
+
"""
|
11
|
+
When a file "dummy.wav" is imported
|
12
|
+
Then the task should have destination "Cart in group MUSIC"
|
13
|
+
|
14
|
+
Scenario: Seletec a cart by number
|
15
|
+
Given a configuration with this prepare block
|
16
|
+
"""
|
17
|
+
cart.number = 123
|
18
|
+
"""
|
19
|
+
When a file "dummy.wav" is imported
|
20
|
+
Then the task should have destination "Cart 123"
|
@@ -0,0 +1,44 @@
|
|
1
|
+
Feature: Manage Cart attributes
|
2
|
+
In order to organize dropboxes
|
3
|
+
An user
|
4
|
+
wants to filter files by name
|
5
|
+
|
6
|
+
Scenario: Select a file by Ruby regexp
|
7
|
+
Given a configuration with this prepare block
|
8
|
+
"""
|
9
|
+
if file.match /dummy/
|
10
|
+
task.tags << 'matched'
|
11
|
+
end
|
12
|
+
"""
|
13
|
+
When a file "dummy.wav" is imported
|
14
|
+
Then the task should have tag "matched"
|
15
|
+
|
16
|
+
Scenario: Select a file with helper 'with'
|
17
|
+
Given a configuration with this prepare block
|
18
|
+
"""
|
19
|
+
with /dummy/ do
|
20
|
+
task.tag 'matched'
|
21
|
+
end
|
22
|
+
"""
|
23
|
+
When a file "dummy.wav" is imported
|
24
|
+
Then the task should have tag "matched"
|
25
|
+
|
26
|
+
Scenario: Select a cast by file name
|
27
|
+
Given a cart "123" exists with title:"A long Title"
|
28
|
+
And a configuration with this prepare block
|
29
|
+
"""
|
30
|
+
cart.find_by_title file.basename
|
31
|
+
"""
|
32
|
+
When a file "a-long-title.wav" is imported
|
33
|
+
Then the task should have destination "Cart 123"
|
34
|
+
|
35
|
+
Scenario: Select a cast by file name
|
36
|
+
Given a cart "123" exists with title:"A long Title", group:"PAD"
|
37
|
+
And a cart "666" exists with title:"A long Title", group:"MUSIC"
|
38
|
+
And a configuration with this prepare block
|
39
|
+
"""
|
40
|
+
cart.find_by_title file.basename, :group => 'PAD'
|
41
|
+
"""
|
42
|
+
When a file "a-long-title.wav" is imported
|
43
|
+
Then the task should have destination "Cart 123"
|
44
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
def import
|
2
|
+
@import ||= Rivendell::Import::Base.new.tap do |import|
|
3
|
+
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
class Array
|
8
|
+
|
9
|
+
def as_hash
|
10
|
+
Hash[self]
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
Given /^a cart "(.*?)" exists with (.*)$/ do |number, fields|
|
16
|
+
attributes = fields.scan(/\ *(([^:]+):"([^\"]+)",?)/).map do |part, name, value|
|
17
|
+
[name, value]
|
18
|
+
end.as_hash
|
19
|
+
|
20
|
+
cart = Rivendell::API::Cart.new(attributes.merge(:number => number))
|
21
|
+
Rivendell::Import::Task.mock_xport.carts << cart
|
22
|
+
end
|
23
|
+
|
24
|
+
Given /^a configuration with this prepare block$/ do |code|
|
25
|
+
import.to_prepare = eval "lambda { |file| " + code + " }"
|
26
|
+
end
|
27
|
+
|
28
|
+
When /^a file "([^"]*)" is imported$/ do |file|
|
29
|
+
import.file file
|
30
|
+
end
|
31
|
+
|
32
|
+
Then /^the task should have destination "([^"]*)"$/ do |destination|
|
33
|
+
import.tasks.pop.destination.should == destination
|
34
|
+
end
|
35
|
+
|
36
|
+
Then /^the task should have tag "([^"]*)"$/ do |tag|
|
37
|
+
import.tasks.pop.tags.should include(tag)
|
38
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
$: << File.dirname(__FILE__) + "/../../lib"
|
2
|
+
|
3
|
+
require "rivendell/import"
|
4
|
+
|
5
|
+
require "logger"
|
6
|
+
Rivendell::Import.logger = ActiveRecord::Base.logger = Logger.new("log/cucumber.log")
|
7
|
+
|
8
|
+
Rivendell::Import.establish_connection "db/test.sqlite3"
|
9
|
+
|
10
|
+
require 'database_cleaner'
|
11
|
+
DatabaseCleaner.strategy = :truncation
|
12
|
+
|
13
|
+
Before do
|
14
|
+
DatabaseCleaner.start
|
15
|
+
end
|
16
|
+
|
17
|
+
After do |scenario|
|
18
|
+
DatabaseCleaner.clean
|
19
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Rivendell::API::MockXport
|
2
|
+
|
3
|
+
def carts
|
4
|
+
@carts ||= []
|
5
|
+
end
|
6
|
+
|
7
|
+
def list_carts(options = {})
|
8
|
+
result = carts
|
9
|
+
if group = options[:group]
|
10
|
+
result = result.select { |cart| cart.group == group }
|
11
|
+
end
|
12
|
+
result
|
13
|
+
end
|
14
|
+
|
15
|
+
def reset!
|
16
|
+
@carts = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
class Rivendell::Import::Task
|
22
|
+
|
23
|
+
@@mock_xport = Rivendell::API::MockXport.new
|
24
|
+
cattr_accessor :mock_xport
|
25
|
+
|
26
|
+
def xport
|
27
|
+
mock_xport
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
Before do
|
33
|
+
Rivendell::Import::Task.mock_xport.reset!
|
34
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require "rivendell/import/version"
|
2
|
+
|
3
|
+
require "null_logger"
|
4
|
+
require "active_support/core_ext/module/attribute_accessors"
|
5
|
+
require "active_support/core_ext/module/delegation"
|
6
|
+
require "active_support/core_ext/enumerable"
|
7
|
+
|
8
|
+
require "rivendell/import/config"
|
9
|
+
|
10
|
+
module Rivendell
|
11
|
+
module Import
|
12
|
+
|
13
|
+
@@config = Config.new
|
14
|
+
def self.config(&block)
|
15
|
+
yield @@config if block_given?
|
16
|
+
@@config
|
17
|
+
end
|
18
|
+
|
19
|
+
@@logger = NullLogger.instance
|
20
|
+
mattr_accessor :logger
|
21
|
+
|
22
|
+
def self.establish_connection(file = "db.sqlite3")
|
23
|
+
ActiveRecord::Base.establish_connection :adapter => "sqlite3", :database => file
|
24
|
+
ActiveRecord::Migrator.migrate(::File.expand_path("../../../db/migrate/", __FILE__), nil)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
require 'listen'
|
31
|
+
|
32
|
+
require 'active_record'
|
33
|
+
ActiveRecord::Base.include_root_in_json = false
|
34
|
+
|
35
|
+
require "rivendell/api"
|
36
|
+
|
37
|
+
require "rivendell/import/worker"
|
38
|
+
require "rivendell/import/task"
|
39
|
+
require "rivendell/import/tasks"
|
40
|
+
require "rivendell/import/base"
|
41
|
+
require "rivendell/import/carts_cache"
|
42
|
+
require "rivendell/import/cart"
|
43
|
+
require "rivendell/import/context"
|
44
|
+
require "rivendell/import/cut"
|
45
|
+
require "rivendell/import/file"
|
46
|
+
require "rivendell/import/notification"
|
47
|
+
require "rivendell/import/notifier/base"
|
48
|
+
require "rivendell/import/notifier/mail"
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module Rivendell::Import
|
4
|
+
class Base
|
5
|
+
|
6
|
+
attr_reader :tasks, :workers
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@tasks = Tasks.new
|
10
|
+
@workers = []
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_accessor :to_prepare
|
14
|
+
|
15
|
+
def listen(directory, options = {})
|
16
|
+
workers << Worker.new(self).start unless options[:dry_run]
|
17
|
+
|
18
|
+
Rivendell::Import.logger.info "Listen files in #{directory}"
|
19
|
+
Listen.to(directory) do |modified, added, removed|
|
20
|
+
added.each do |file|
|
21
|
+
Rivendell::Import.logger.debug "Detected file '#{file}'"
|
22
|
+
file(file, directory)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def process(*paths)
|
28
|
+
paths.flatten.each do |path|
|
29
|
+
method = ::File.directory?(path) ? :directory : :file
|
30
|
+
send method, path
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def file(path, base_directory = nil)
|
35
|
+
file = Rivendell::Import::File.new path, :base_directory => base_directory
|
36
|
+
create_task file
|
37
|
+
end
|
38
|
+
|
39
|
+
def directory(directory)
|
40
|
+
Dir[::File.join(directory, "**/*")].each do |file|
|
41
|
+
file(file, directory) if ::File.file?(file)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def create_task(file)
|
46
|
+
Rivendell::Import.logger.debug "Create task for #{file}"
|
47
|
+
tasks.create(file) do |task|
|
48
|
+
prepare_task task
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def prepare_task(task)
|
53
|
+
task.prepare(&to_prepare) if to_prepare
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|