rivendell-import 0.7 → 0.8

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/Gemfile CHANGED
@@ -5,7 +5,17 @@ gemspec
5
5
  # gem "rivendell-db", :path => "~/Projects/RivendellDb"
6
6
  # gem "rivendell-api", :path => "~/Projects/RivendellApi"
7
7
 
8
+ # To test mysql DB instead of sqlite
9
+ #
10
+ # $ mysqladmin create import
11
+ # $ mysql mysql
12
+ # mysql> GRANT ALL PRIVILEGES ON import.* TO 'import'@'localhost' IDENTIFIED BY 'import';
13
+ #
14
+ # and this gem :
15
+ # gem "mysql"
16
+
8
17
  gem 'capistrano'
18
+ gem 'simplecov-rcov'
9
19
 
10
20
  if RUBY_PLATFORM =~ /linux/
11
21
  gem 'libnotify'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rivendell-import (0.7)
4
+ rivendell-import (0.8)
5
5
  SyslogLogger (~> 2.0)
6
6
  activerecord (~> 3.2.8)
7
7
  activesupport (~> 3.2.8)
@@ -21,32 +21,33 @@ GEM
21
21
  remote: https://rubygems.org/
22
22
  specs:
23
23
  SyslogLogger (2.0)
24
- activemodel (3.2.16)
25
- activesupport (= 3.2.16)
24
+ activemodel (3.2.17)
25
+ activesupport (= 3.2.17)
26
26
  builder (~> 3.0.0)
27
- activerecord (3.2.16)
28
- activemodel (= 3.2.16)
29
- activesupport (= 3.2.16)
27
+ activerecord (3.2.17)
28
+ activemodel (= 3.2.17)
29
+ activesupport (= 3.2.17)
30
30
  arel (~> 3.0.2)
31
31
  tzinfo (~> 0.3.29)
32
- activesupport (3.2.16)
32
+ activesupport (3.2.17)
33
33
  i18n (~> 0.6, >= 0.6.4)
34
34
  multi_json (~> 1.0)
35
35
  addressable (2.3.5)
36
36
  arel (3.0.3)
37
37
  bcrypt-ruby (3.1.2)
38
- builder (3.0.3)
38
+ builder (3.0.4)
39
39
  capistrano (2.14.2)
40
40
  highline
41
41
  net-scp (>= 1.0.0)
42
42
  net-sftp (>= 2.0.0)
43
43
  net-ssh (>= 2.0.14)
44
44
  net-ssh-gateway (>= 1.1.0)
45
- cucumber (1.2.1)
45
+ cucumber (1.3.10)
46
46
  builder (>= 2.1.2)
47
47
  diff-lcs (>= 1.1.3)
48
- gherkin (~> 2.11.0)
49
- json (>= 1.4.6)
48
+ gherkin (~> 2.12)
49
+ multi_json (>= 1.7.5, < 2.0)
50
+ multi_test (>= 0.0.2)
50
51
  daemons (1.1.9)
51
52
  data_objects (0.10.13)
52
53
  addressable (~> 2.1)
@@ -80,8 +81,8 @@ GEM
80
81
  data_objects (= 0.10.13)
81
82
  fastercsv (1.5.5)
82
83
  ffi (1.9.3)
83
- gherkin (2.11.2)
84
- json (>= 1.4.6)
84
+ gherkin (2.12.2)
85
+ multi_json (~> 1.3)
85
86
  guard (1.4.0)
86
87
  listen (>= 0.4.2)
87
88
  thor (>= 0.14.6)
@@ -112,6 +113,7 @@ GEM
112
113
  treetop (~> 1.4.8)
113
114
  mime-types (1.25.1)
114
115
  multi_json (1.8.2)
116
+ multi_test (0.0.3)
115
117
  multi_xml (0.5.5)
116
118
  multipart-post (1.2.0)
117
119
  net-scp (1.1.0)
@@ -122,7 +124,7 @@ GEM
122
124
  net-ssh-gateway (1.2.0)
123
125
  net-ssh (>= 2.6.5)
124
126
  null_logger (0.0.1)
125
- polyglot (0.3.3)
127
+ polyglot (0.3.4)
126
128
  rack (1.5.2)
127
129
  rack-protection (1.5.1)
128
130
  rack
@@ -156,11 +158,13 @@ GEM
156
158
  multi_json (~> 1.0)
157
159
  simplecov-html (~> 0.5.3)
158
160
  simplecov-html (0.5.3)
161
+ simplecov-rcov (0.2.3)
162
+ simplecov (>= 0.4.1)
159
163
  sinatra (1.4.4)
160
164
  rack (~> 1.4)
161
165
  rack-protection (~> 1.4)
162
166
  tilt (~> 1.3, >= 1.3.4)
163
- sqlite3 (1.3.8)
167
+ sqlite3 (1.3.9)
164
168
  stringex (1.5.1)
165
169
  thor (0.16.0)
166
170
  tilt (1.4.1)
@@ -168,7 +172,7 @@ GEM
168
172
  polyglot
169
173
  polyglot (>= 0.3.1)
170
174
  trollop (2.0)
171
- tzinfo (0.3.38)
175
+ tzinfo (0.3.39)
172
176
  uuidtools (2.1.4)
173
177
  will_paginate (3.0.5)
174
178
 
@@ -188,3 +192,4 @@ DEPENDENCIES
188
192
  rivendell-import!
189
193
  rspec
190
194
  simplecov
195
+ simplecov-rcov
data/README.md CHANGED
@@ -1,29 +1,18 @@
1
1
  # Rivendell::Import
2
2
 
3
- TODO: Write a gem description
3
+ Next-Generation import interface for Rivendell
4
4
 
5
- ## Installation
5
+ ## Run examples
6
6
 
7
- Add this line to your application's Gemfile:
7
+ bundle exec ./bin/rivendell-import --config examples/config.rb --listen examples --debug
8
8
 
9
- gem 'rivendell-import'
9
+ ## Initialize a dedicated MySQL database
10
10
 
11
- And then execute:
11
+ $ mysqladmin create import
12
+ $ mysql mysql
13
+ mysql> GRANT ALL PRIVILEGES ON import.* TO 'import'@'localhost' IDENTIFIED BY 'import';
14
+ $ mysqladmin flush-privileges
12
15
 
13
- $ bundle
16
+ Then use :
14
17
 
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
18
+ rivendell-import [...] --database 'mysql://import:import@localhost/import' [...]
data/examples/.gitignore CHANGED
@@ -1,2 +1,4 @@
1
1
  music/
2
2
  pad/
3
+ *.wav
4
+ *.mp3
data/examples/config.rb CHANGED
@@ -24,6 +24,8 @@ Rivendell::Import.config do |config|
24
24
  config.rivendell.db_url = 'mysql://rduser:letmein@localhost/Rivendell'
25
25
 
26
26
  config.to_prepare do |file|
27
+ # task.cancel!
28
+
27
29
  cart.default_title = file.basename
28
30
 
29
31
  file.in("music") do
@@ -51,16 +51,44 @@ module Rivendell::Import
51
51
  end
52
52
 
53
53
  def update
54
- update_attributes = attributes.dup
54
+ begin
55
+ update_by_api
56
+ rescue => e
57
+ Rivendell::Import.logger.debug "Update by API failed : #{e}"
58
+ update_by_db if Database.enabled?
59
+ end
60
+ end
55
61
 
56
- if default_title
57
- current_cart = xport.list_cart(number)
58
- unless current_cart.has_title?
59
- update_attributes[:title] = default_title
60
- end
62
+ def empty_title?(title)
63
+ not [ nil, "", "[new cart]" ].include? title
64
+ end
65
+
66
+ def update_by_api
67
+ update_attributes = {}
68
+
69
+ if title
70
+ update_attributes[:title] = title
71
+ else
72
+ update_attributes[:title] = default_title if default_title && empty_title?(xport.list_cart(number).title)
61
73
  end
62
74
 
63
- xport.edit_cart number, update_attributes
75
+ unless update_attributes.empty?
76
+ Rivendell::Import.logger.debug "Update Cart by API : #{update_attributes}"
77
+ xport.edit_cart number, update_attributes
78
+ end
79
+ end
80
+
81
+ def update_by_db
82
+ Database.init
83
+
84
+ Rivendell::Import.logger.debug "Update Cart by DB"
85
+ current_cart = Rivendell::DB::Cart.get(number)
86
+ if title
87
+ current_cart.title = title
88
+ else
89
+ current_cart.title = default_title if default_title && empty_title?(current_cart.title)
90
+ end
91
+ current_cart.save
64
92
  end
65
93
 
66
94
  def cut
@@ -16,7 +16,11 @@ module Rivendell::Import
16
16
  end
17
17
 
18
18
  def as_json(options = {})
19
- super options.merge(:root => false)
19
+ super(options.merge(:root => false)).tap do |as_json|
20
+ as_json.each do |k,v|
21
+ as_json[k] = [v.begin, v.end] if v.is_a?(Range)
22
+ end
23
+ end
20
24
  end
21
25
 
22
26
  def attributes
@@ -70,5 +74,16 @@ module Rivendell::Import
70
74
  end
71
75
  end
72
76
 
77
+ def datetime=(datetime)
78
+ datetime = (datetime.first)..(datetime.last) if Array === datetime
79
+ datetime = Time.parse(datetime.begin)..Time.parse(datetime.end) if String === datetime.first
80
+ @datetime = datetime
81
+ end
82
+
83
+ def daypart=(daypart)
84
+ daypart = (daypart.first)..(daypart.last) if Array === daypart
85
+ @daypart = daypart
86
+ end
87
+
73
88
  end
74
89
  end
@@ -20,8 +20,10 @@ module Rivendell::Import
20
20
  self.pending.select(&:ready?)
21
21
  end
22
22
 
23
+ RAN_STATUSES = %w{completed failed canceled}.freeze
24
+
23
25
  def self.ran
24
- where :status => %w{completed failed}
26
+ where :status => RAN_STATUSES
25
27
  end
26
28
 
27
29
  def self.search(text)
@@ -29,7 +31,7 @@ module Rivendell::Import
29
31
  end
30
32
 
31
33
  def ran?
32
- status.completed? or status.failed?
34
+ status.in? RAN_STATUSES
33
35
  end
34
36
 
35
37
  @@default_xport_options = {}
@@ -99,7 +101,16 @@ module Rivendell::Import
99
101
  file.destroy! if delete_file?
100
102
  end
101
103
 
104
+ def cancel!
105
+ self.status = "canceled"
106
+ end
107
+
102
108
  def run
109
+ if status.canceled?
110
+ logger.debug "Don't run canceled task : #{self.inspect}"
111
+ return
112
+ end
113
+
103
114
  logger.debug "Run #{self.inspect}"
104
115
  change_status! :running
105
116
 
@@ -117,7 +128,7 @@ module Rivendell::Import
117
128
  logger.error "Task failed : #{e}"
118
129
  logger.debug e.backtrace.join("\n")
119
130
  ensure
120
- unless status.completed?
131
+ unless ran?
121
132
  change_status! :failed
122
133
  end
123
134
  save!
@@ -1,5 +1,5 @@
1
1
  module Rivendell
2
2
  module Import
3
- VERSION = "0.7"
3
+ VERSION = "0.8"
4
4
  end
5
5
  end
@@ -19,8 +19,15 @@ module Rivendell
19
19
  @@logger = NullLogger.instance
20
20
  mattr_accessor :logger
21
21
 
22
- def self.establish_connection(file = "db.sqlite3")
23
- ActiveRecord::Base.establish_connection :adapter => "sqlite3", :database => file
22
+ def self.establish_connection(file_or_uri = "db.sqlite3")
23
+ database_spec =
24
+ if URI.parse(file_or_uri).scheme.in? [nil, "file"]
25
+ { :adapter => "sqlite3", :database => file_or_uri }
26
+ else
27
+ file_or_uri
28
+ end
29
+
30
+ ActiveRecord::Base.establish_connection database_spec
24
31
  ActiveRecord::Migrator.migrate(::File.expand_path("../../../db/migrate/", __FILE__), nil)
25
32
  end
26
33
 
@@ -44,6 +44,6 @@ Gem::Specification.new do |gem|
44
44
  gem.add_development_dependency "rdoc"
45
45
  gem.add_development_dependency "cucumber"
46
46
  gem.add_development_dependency "database_cleaner"
47
- # gem.add_development_dependency "remarkable_activerecord"
48
47
 
48
+ # gem.add_development_dependency "remarkable_activerecord"
49
49
  end
@@ -46,12 +46,11 @@ describe Rivendell::Import::Base do
46
46
  let(:file) { Rivendell::Import::File.new("dummy.wav") }
47
47
 
48
48
  it "should create a File with given path and base_directory" do
49
- Rivendell::Import::File.should_receive(:new).with(File.expand_path("path", "base_directory"), :base_directory => "base_directory")
50
- subject.file "path", "base_directory"
49
+ subject.file("path", "base_directory").file_path.should == File.expand_path("path", "base_directory")
51
50
  end
52
51
 
53
52
  it "should create a File with given path and base_directory" do
54
- Rivendell::Import::File.stub :new=> file
53
+ Rivendell::Import::File.stub :new => file
55
54
  subject.should_receive(:create_task).with(file)
56
55
  subject.file "path", "base_directory"
57
56
  end
@@ -14,6 +14,26 @@ describe Rivendell::Import::Cut do
14
14
 
15
15
  end
16
16
 
17
+ describe "#to_json" do
18
+
19
+ let(:json_clone) do
20
+ Rivendell::Import::Cut.new(cart).tap do |clone|
21
+ clone.from_json subject.to_json, false
22
+ end
23
+ end
24
+
25
+ it "should support datetime (Time range)" do
26
+ subject.datetime = Time.parse("2014-03-20 00:00")..Time.parse("2014-03-21 23:59:59")
27
+ json_clone.datetime.should == subject.datetime
28
+ end
29
+
30
+ it "should support datepart (String range)" do
31
+ subject.daypart = "08:00:00".."12:00:00"
32
+ json_clone.daypart.should == subject.daypart
33
+ end
34
+
35
+ end
36
+
17
37
  describe "#create" do
18
38
 
19
39
  before(:each) do
@@ -39,6 +59,7 @@ describe Rivendell::Import::Cut do
39
59
 
40
60
  before do
41
61
  subject.number = 1
62
+ subject.cart.number = 1
42
63
  end
43
64
 
44
65
  context "when DB attributes are defined" do
@@ -6,7 +6,7 @@ describe Rivendell::Import::Task do
6
6
  subject { Rivendell::Import::Task.new :file => file }
7
7
 
8
8
  describe "#file" do
9
-
9
+
10
10
  it "should return a file with specified path" do
11
11
  Rivendell::Import::Task.new(:file => file).file.should == file
12
12
  end
@@ -14,7 +14,7 @@ describe Rivendell::Import::Task do
14
14
  end
15
15
 
16
16
  describe "#cart" do
17
-
17
+
18
18
  it "should return a Cart associated to the task" do
19
19
  subject.cart.task.should == subject
20
20
  end
@@ -22,7 +22,7 @@ describe Rivendell::Import::Task do
22
22
  end
23
23
 
24
24
  describe "#xport" do
25
-
25
+
26
26
  it "should return a instance of Rivendell::API::Xport" do
27
27
  subject.xport.should be_instance_of(Rivendell::API::Xport)
28
28
  end
@@ -35,14 +35,14 @@ describe Rivendell::Import::Task do
35
35
  end
36
36
 
37
37
  describe "#xport_options" do
38
-
38
+
39
39
  it "should use #default_xport_options" do
40
- subject.stub :default_xport_options => { :host => "dummy" }
40
+ subject.stub :default_xport_options => { :host => "dummy" }
41
41
  subject.xport_options.should == { :host => "dummy" }
42
42
  end
43
43
 
44
44
  it "should not modified #default_xport_options" do
45
- subject.stub :default_xport_options => { :host => "dummy" }
45
+ subject.stub :default_xport_options => { :host => "dummy" }
46
46
  subject.xport_options[:host] = "other"
47
47
  subject.default_xport_options.should == { :host => "dummy" }
48
48
  end
@@ -50,14 +50,14 @@ describe Rivendell::Import::Task do
50
50
  end
51
51
 
52
52
  describe "#prepare" do
53
-
53
+
54
54
  it "should return the Task" do
55
55
  subject.prepare { |file| } .should == subject
56
56
  end
57
57
 
58
58
  it "should invoke the specified block with Task file" do
59
59
  given_file = nil
60
- subject.prepare do |file|
60
+ subject.prepare do |file|
61
61
  given_file = file
62
62
  end
63
63
  given_file.should == subject.file
@@ -71,7 +71,23 @@ describe Rivendell::Import::Task do
71
71
  subject.stub :destination => "test"
72
72
  subject.stub :cart => mock(:create => true, :import => true, :update => true, :number => 123, :to_json => '')
73
73
  end
74
-
74
+
75
+ context "when task is canceled" do
76
+ before do
77
+ subject.status = "canceled"
78
+ end
79
+
80
+ it "should not create cart" do
81
+ subject.cart.should_not_receive(:create)
82
+ subject.run
83
+ end
84
+
85
+ it "keeps its canceled status" do
86
+ subject.run
87
+ expect(subject.status).to be_canceled
88
+ end
89
+ end
90
+
75
91
  it "should create Cart" do
76
92
  subject.cart.should_receive(:create)
77
93
  subject.run
@@ -101,7 +117,7 @@ describe Rivendell::Import::Task do
101
117
  end
102
118
 
103
119
  describe "#destination" do
104
-
120
+
105
121
  it "should return 'Cart in group :group' if cart#group is defined" do
106
122
  subject.cart.group = 'dummy'
107
123
  subject.destination.should == "Cart in group dummy"
@@ -115,7 +131,7 @@ describe Rivendell::Import::Task do
115
131
  end
116
132
 
117
133
  describe "#tags" do
118
-
134
+
119
135
  it "should be empty by default" do
120
136
  subject.tags.should be_empty
121
137
  end
@@ -123,12 +139,12 @@ describe Rivendell::Import::Task do
123
139
  end
124
140
 
125
141
  describe "#tag" do
126
-
142
+
127
143
  it "should add the given tag" do
128
144
  subject.tag "dummy"
129
145
  subject.tags.should == %w{dummy}
130
146
  end
131
-
147
+
132
148
  end
133
149
 
134
150
  describe "storage" do
@@ -163,14 +179,14 @@ describe Rivendell::Import::Task do
163
179
  subject.xport_options[:host] = "dummy"
164
180
  reloaded_task.xport_options[:host].should == "dummy"
165
181
  end
166
-
182
+
167
183
  end
168
184
 
169
185
  describe "#status" do
170
-
186
+
171
187
  it "should be include in pending, completed, failed" do
172
188
  pending
173
- # subject.should validate_inclusion_of(:status, :in => %w{pending running completed failed})
189
+ # subject.should validate_inclusion_of(:status, :in => %w{pending running completed failed canceled})
174
190
  end
175
191
 
176
192
  it "should be pending by default" do
@@ -180,7 +196,7 @@ describe Rivendell::Import::Task do
180
196
  end
181
197
 
182
198
  describe "#notifications" do
183
-
199
+
184
200
  before(:each) do
185
201
  subject.save!
186
202
  end
@@ -198,7 +214,7 @@ describe Rivendell::Import::Task do
198
214
  end
199
215
 
200
216
  let(:notifier) { Rivendell::Import::Notifier::Test.create! }
201
-
217
+
202
218
  it "should create a Notification when a Notifier is added" do
203
219
  subject.notifiers << notifier
204
220
  subject.notifications.first.notifier.should == notifier
@@ -207,7 +223,7 @@ describe Rivendell::Import::Task do
207
223
  end
208
224
 
209
225
  describe "#notify!" do
210
-
226
+
211
227
  before(:each) do
212
228
  subject.status = "completed"
213
229
  subject.save!
@@ -215,7 +231,7 @@ describe Rivendell::Import::Task do
215
231
  end
216
232
 
217
233
  let(:notifier) { Rivendell::Import::Notifier::Test.create! }
218
-
234
+
219
235
  it "should notify task with all associated notifiers" do
220
236
  subject.notify!
221
237
  notifier.notified_tasks.should == [ subject ]
@@ -229,7 +245,7 @@ describe Rivendell::Import::Task do
229
245
  end
230
246
 
231
247
  describe "#change_status!" do
232
-
248
+
233
249
  it "should update_attribute :status" do
234
250
  subject.should_receive(:update_attribute).with(:status, "completed")
235
251
  subject.change_status! :completed
@@ -248,7 +264,7 @@ describe Rivendell::Import::Task do
248
264
  end
249
265
 
250
266
  describe "#delete_file!" do
251
-
267
+
252
268
  it "should set flag delete_file" do
253
269
  subject.delete_file!
254
270
  subject.delete_file.should be_true
@@ -259,14 +275,14 @@ describe Rivendell::Import::Task do
259
275
  before do
260
276
  subject.stub :cart => mock.as_null_object
261
277
  end
262
-
278
+
263
279
 
264
280
  it "should destroy! file when task is completed" do
265
281
  subject.delete_file!
266
282
  subject.file.should_receive(:destroy!)
267
283
  subject.run
268
284
  end
269
-
285
+
270
286
  end
271
287
 
272
288
  context "not defined" do
@@ -275,13 +291,13 @@ describe Rivendell::Import::Task do
275
291
  subject.file.should_not_receive(:destroy!)
276
292
  subject.run
277
293
  end
278
-
294
+
279
295
  end
280
296
 
281
297
  end
282
298
 
283
299
  describe ".purge!" do
284
-
300
+
285
301
  it "should remove tasks older than 24 hours" do
286
302
  old_task = Rivendell::Import::Task.create! :file => file, :created_at => 25.hours.ago
287
303
  Rivendell::Import::Task.purge!
@@ -301,4 +317,51 @@ describe Rivendell::Import::Task do
301
317
 
302
318
  end
303
319
 
320
+ describe "#ran?" do
321
+
322
+ it "should be true when status is completed" do
323
+ subject.status = "completed"
324
+ expect(subject).to be_ran
325
+ end
326
+
327
+ it "should be true when status is failed" do
328
+ subject.status = "failed"
329
+ expect(subject).to be_ran
330
+ end
331
+
332
+ it "should be true when status is canceled" do
333
+ subject.status = "canceled"
334
+ expect(subject).to be_ran
335
+ end
336
+
337
+ end
338
+
339
+ describe ".ran" do
340
+
341
+ it "should return completed tasks" do
342
+ subject.change_status! "completed"
343
+ expect(Rivendell::Import::Task.ran).to include(subject)
344
+ end
345
+
346
+ it "should return failed tasks" do
347
+ subject.change_status! "failed"
348
+ expect(Rivendell::Import::Task.ran).to include(subject)
349
+ end
350
+
351
+ it "should return canceled tasks" do
352
+ subject.change_status! "canceled"
353
+ expect(Rivendell::Import::Task.ran).to include(subject)
354
+ end
355
+
356
+ end
357
+
358
+ describe "#cancel!" do
359
+
360
+ it "should change task status to canceled" do
361
+ subject.cancel!
362
+ expect(subject.status).to be_canceled
363
+ end
364
+
365
+ end
366
+
304
367
  end