rivendell-import 0.0.1
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/.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
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'mail'
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
module Rivendell::Import::Notifier
|
5
|
+
class Mail < Rivendell::Import::Notifier::Base
|
6
|
+
|
7
|
+
@@from = nil
|
8
|
+
cattr_accessor :from
|
9
|
+
|
10
|
+
attr_accessor :from, :to, :subject, :body
|
11
|
+
|
12
|
+
def subject
|
13
|
+
@subject ||= File.expand_path("../mail-subject.erb", __FILE__)
|
14
|
+
end
|
15
|
+
|
16
|
+
def body
|
17
|
+
@body ||= File.expand_path("../mail-body.erb", __FILE__)
|
18
|
+
end
|
19
|
+
|
20
|
+
def from
|
21
|
+
@from ||= self.class.from
|
22
|
+
end
|
23
|
+
|
24
|
+
def notify!(tasks)
|
25
|
+
create_message(tasks).deliver!
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_message(tasks)
|
29
|
+
Message.new(tasks).tap do |mail|
|
30
|
+
mail.from = from
|
31
|
+
mail.to = to
|
32
|
+
mail.subject = template(subject)
|
33
|
+
mail.body = template(body)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Message
|
38
|
+
|
39
|
+
attr_reader :tasks
|
40
|
+
attr_accessor :from, :to, :subject, :body
|
41
|
+
|
42
|
+
def initialize(tasks)
|
43
|
+
@tasks = tasks
|
44
|
+
end
|
45
|
+
|
46
|
+
def completed
|
47
|
+
tasks.select { |task| task.status.completed? }
|
48
|
+
end
|
49
|
+
|
50
|
+
def failed
|
51
|
+
tasks.select { |task| task.status.failed? }
|
52
|
+
end
|
53
|
+
|
54
|
+
def failed?
|
55
|
+
failed.present?
|
56
|
+
end
|
57
|
+
|
58
|
+
delegate :many?, :to => :tasks
|
59
|
+
|
60
|
+
def mail
|
61
|
+
::Mail.new.tap do |mail|
|
62
|
+
mail.from = from
|
63
|
+
mail.to = to
|
64
|
+
mail.subject = strip(render(subject))
|
65
|
+
mail.body = render(body)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def deliver!
|
70
|
+
mail.deliver!
|
71
|
+
end
|
72
|
+
|
73
|
+
def render(template)
|
74
|
+
ERB.new(template, nil, '%<>-').result(binding)
|
75
|
+
end
|
76
|
+
|
77
|
+
def strip(text)
|
78
|
+
text.strip.gsub(/\n[ ]*/m,"")
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
# def valid?
|
84
|
+
# [from, to, subject, body].all?(&:present?)
|
85
|
+
# end
|
86
|
+
|
87
|
+
def parameters
|
88
|
+
%w{from to subject body}.inject({}) do |map, attribute|
|
89
|
+
value = send attribute
|
90
|
+
map[attribute] = value if value
|
91
|
+
map
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def template(definition)
|
96
|
+
if File.exists?(definition)
|
97
|
+
File.read definition
|
98
|
+
else
|
99
|
+
definition
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Rivendell::Import
|
2
|
+
class Notifiers
|
3
|
+
|
4
|
+
attr_reader :import, :notifiers
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@import = import
|
8
|
+
end
|
9
|
+
|
10
|
+
def push(notifier)
|
11
|
+
notifiers << notifier
|
12
|
+
end
|
13
|
+
|
14
|
+
def notify!
|
15
|
+
notified_tasks = waiting_tasks
|
16
|
+
@waiting_tasks = []
|
17
|
+
|
18
|
+
notifiers.each do |notifier|
|
19
|
+
notifier.notify notified_tasks
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'rivendell/import/tasking/file'
|
2
|
+
require 'rivendell/import/tasking/tags'
|
3
|
+
require 'rivendell/import/tasking/cart'
|
4
|
+
require 'rivendell/import/tasking/status'
|
5
|
+
require 'rivendell/import/tasking/destination'
|
6
|
+
|
7
|
+
module Rivendell::Import
|
8
|
+
class Task < ActiveRecord::Base
|
9
|
+
include Rivendell::Import::Tasking::File
|
10
|
+
include Rivendell::Import::Tasking::Tags
|
11
|
+
include Rivendell::Import::Tasking::Cart
|
12
|
+
include Rivendell::Import::Tasking::Status
|
13
|
+
include Rivendell::Import::Tasking::Destination
|
14
|
+
|
15
|
+
def self.pending
|
16
|
+
where :status => "pending"
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.ran
|
20
|
+
where :status => %w{completed failed}
|
21
|
+
end
|
22
|
+
|
23
|
+
def ran?
|
24
|
+
status.completed? or status.failed?
|
25
|
+
end
|
26
|
+
|
27
|
+
def xport
|
28
|
+
@xport ||= Rivendell::API::Xport.new
|
29
|
+
end
|
30
|
+
|
31
|
+
def prepare(&block)
|
32
|
+
begin
|
33
|
+
Context.new(self).run(&block)
|
34
|
+
rescue => e
|
35
|
+
logger.error "Task preparation failed : #{e}"
|
36
|
+
end
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def logger
|
41
|
+
Rivendell::Import.logger
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
"Import '#{file}' in #{destination}"
|
46
|
+
end
|
47
|
+
|
48
|
+
has_many :notifications
|
49
|
+
has_many :notifiers, :through => :notifications
|
50
|
+
|
51
|
+
def notify!
|
52
|
+
notifiers.each do |notifier|
|
53
|
+
notifier.notify
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def run
|
58
|
+
logger.debug "Run #{self.inspect}"
|
59
|
+
change_status! :running
|
60
|
+
|
61
|
+
reset_destination!
|
62
|
+
|
63
|
+
cart.create
|
64
|
+
cart.import file
|
65
|
+
cart.update
|
66
|
+
|
67
|
+
save!
|
68
|
+
change_status! :completed
|
69
|
+
|
70
|
+
logger.info "Imported Cart #{cart.number}"
|
71
|
+
rescue Exception => e
|
72
|
+
logger.error "Task failed : #{e}"
|
73
|
+
ensure
|
74
|
+
unless status.completed?
|
75
|
+
change_status! :failed
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Rivendell::Import::Tasking
|
2
|
+
module Cart
|
3
|
+
|
4
|
+
def raw_cart
|
5
|
+
read_attribute :cart
|
6
|
+
end
|
7
|
+
|
8
|
+
def cart
|
9
|
+
@cast ||= Rivendell::Import::Cart.new(self).tap do |cart|
|
10
|
+
cart.from_json raw_cart if raw_cart
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def write_cart
|
15
|
+
write_attribute :cart, (cart.present? ? cart.to_json : nil)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.included(base)
|
19
|
+
base.class_eval do
|
20
|
+
before_save :write_cart
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Rivendell::Import::Tasking
|
2
|
+
module Destination
|
3
|
+
|
4
|
+
def destination
|
5
|
+
read_attribute(:destination) or
|
6
|
+
write_attribute(:destination, calculate_destination)
|
7
|
+
end
|
8
|
+
|
9
|
+
def reset_destination!
|
10
|
+
write_attribute :destination, nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.included(base)
|
14
|
+
base.class_eval do
|
15
|
+
before_save :destination, :on => :create
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def calculate_destination
|
20
|
+
if cart.number
|
21
|
+
"Cart #{cart.number}"
|
22
|
+
elsif cart.group
|
23
|
+
"Cart in group #{cart.group}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Rivendell::Import::Tasking
|
2
|
+
module File
|
3
|
+
def file=(file)
|
4
|
+
if file
|
5
|
+
@file = file
|
6
|
+
|
7
|
+
self.file_name = file.name
|
8
|
+
self.file_path = file.path
|
9
|
+
else
|
10
|
+
@file = nil
|
11
|
+
|
12
|
+
self.file_name = self.file_path = nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def file
|
17
|
+
@file ||= Rivendell::Import::File.new(file_name, :path => file_path)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Rivendell::Import::Tasking
|
2
|
+
module Status
|
3
|
+
|
4
|
+
def define_default_status
|
5
|
+
self.status ||= "pending"
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.included(base)
|
9
|
+
base.class_eval do
|
10
|
+
after_initialize :define_default_status
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def raw_status
|
15
|
+
read_attribute(:status)
|
16
|
+
end
|
17
|
+
|
18
|
+
def status
|
19
|
+
ActiveSupport::StringInquirer.new(raw_status) if raw_status
|
20
|
+
end
|
21
|
+
|
22
|
+
def change_status!(status)
|
23
|
+
logger.debug "Change status to #{status}"
|
24
|
+
update_attribute :status, status.to_s
|
25
|
+
notify! if ran?
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Rivendell::Import::Tasking
|
2
|
+
module Tags
|
3
|
+
|
4
|
+
def raw_tags
|
5
|
+
read_attribute :tags
|
6
|
+
end
|
7
|
+
|
8
|
+
def tags
|
9
|
+
@tags ||= (raw_tags ? raw_tags.split(",") : [])
|
10
|
+
end
|
11
|
+
|
12
|
+
def tag(tag)
|
13
|
+
self.tags << tag
|
14
|
+
end
|
15
|
+
|
16
|
+
def write_tags
|
17
|
+
write_attribute :tags, tags.join(',') if @tags
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.included(base)
|
21
|
+
base.class_eval do
|
22
|
+
before_save :write_tags
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Rivendell::Import
|
2
|
+
class Tasks
|
3
|
+
|
4
|
+
def pending?
|
5
|
+
not Task.pending.empty?
|
6
|
+
end
|
7
|
+
|
8
|
+
def pop
|
9
|
+
Task.pending.first
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
Task.pending.find_each(&:run)
|
14
|
+
end
|
15
|
+
|
16
|
+
def create(file, &block)
|
17
|
+
Rivendell::Import::Task.create({:file => file}, {}, &block).tap do |task|
|
18
|
+
Rivendell::Import.logger.debug "Created task #{task.inspect}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Rivendell::Import
|
2
|
+
class Worker
|
3
|
+
|
4
|
+
attr_reader :import
|
5
|
+
|
6
|
+
def initialize(import)
|
7
|
+
@import = import
|
8
|
+
end
|
9
|
+
|
10
|
+
def start
|
11
|
+
Thread.new do
|
12
|
+
Rivendell::Import.logger.debug "Start Worker"
|
13
|
+
run
|
14
|
+
end
|
15
|
+
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
loop do
|
21
|
+
task = import.tasks.pop
|
22
|
+
if task
|
23
|
+
task.run
|
24
|
+
else
|
25
|
+
# Rivendell::Import.logger.debug "No pending task, sleep 10s"
|
26
|
+
sleep 10
|
27
|
+
end
|
28
|
+
end
|
29
|
+
rescue => e
|
30
|
+
Rivendell::Import.logger.error "Worker failed : #{e}"
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/rivendell/import/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Alban Peignier"]
|
6
|
+
gem.email = ["alban@tryphon.eu"]
|
7
|
+
gem.description = %q{Import sound in our Rivendell system}
|
8
|
+
gem.summary = %q{Import engine for Rivendell}
|
9
|
+
gem.homepage = "http://wiki.tryphon.eu/rivendell-import/"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "rivendell-import"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Rivendell::Import::VERSION
|
17
|
+
|
18
|
+
gem.add_runtime_dependency 'listen'
|
19
|
+
gem.add_runtime_dependency 'httmultiparty'
|
20
|
+
gem.add_runtime_dependency 'rivendell-api', '~> 0.0.2'
|
21
|
+
gem.add_runtime_dependency 'trollop'
|
22
|
+
gem.add_runtime_dependency 'activerecord', '~> 3.2.8'
|
23
|
+
gem.add_runtime_dependency 'activesupport', '~> 3.2.8'
|
24
|
+
gem.add_runtime_dependency 'mail'
|
25
|
+
gem.add_runtime_dependency 'sqlite3'
|
26
|
+
|
27
|
+
gem.add_development_dependency "simplecov"
|
28
|
+
gem.add_development_dependency "rspec"
|
29
|
+
gem.add_development_dependency "guard"
|
30
|
+
gem.add_development_dependency "guard-rspec"
|
31
|
+
gem.add_development_dependency "guard-cucumber"
|
32
|
+
gem.add_development_dependency "rake"
|
33
|
+
gem.add_development_dependency "cucumber"
|
34
|
+
gem.add_development_dependency "database_cleaner"
|
35
|
+
# gem.add_development_dependency "remarkable_activerecord"
|
36
|
+
|
37
|
+
end
|