rivendell-import 0.7 → 0.8

Sign up to get free protection for your applications and to get access to all the features.
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