kithe 2.0.0.pre.alpha2 → 2.0.0.pre.beta1

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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/app/jobs/kithe/create_derivatives_job.rb +2 -2
  3. data/app/models/kithe/asset.rb +82 -154
  4. data/app/models/kithe/asset/derivative_creator.rb +32 -62
  5. data/app/models/kithe/asset/derivative_definition.rb +12 -13
  6. data/app/models/kithe/asset/set_shrine_uploader.rb +64 -0
  7. data/app/models/kithe/collection.rb +0 -6
  8. data/app/models/kithe/model.rb +0 -21
  9. data/app/models/kithe/work.rb +0 -5
  10. data/app/uploaders/kithe/asset_uploader.rb +15 -78
  11. data/lib/kithe/version.rb +4 -1
  12. data/lib/shrine/plugins/kithe_checksum_signatures.rb +41 -0
  13. data/lib/shrine/plugins/kithe_controllable_backgrounding.rb +53 -0
  14. data/lib/shrine/plugins/kithe_derivative_definitions.rb +101 -0
  15. data/lib/shrine/plugins/kithe_derivatives.rb +54 -0
  16. data/lib/shrine/plugins/kithe_determine_mime_type.rb +39 -0
  17. data/lib/shrine/plugins/kithe_persisted_derivatives.rb +161 -0
  18. data/lib/shrine/plugins/kithe_promotion_callbacks.rb +4 -0
  19. data/lib/shrine/plugins/kithe_promotion_directives.rb +33 -3
  20. data/lib/shrine/plugins/kithe_storage_location.rb +53 -4
  21. data/lib/tasks/kithe_tasks.rake +22 -15
  22. data/spec/dummy/log/development.log +867 -0
  23. data/spec/dummy/log/test.log +26005 -0
  24. data/spec/models/kithe/asset/asset_derivatives_spec.rb +137 -0
  25. data/spec/models/kithe/asset/asset_promotion_hooks_spec.rb +26 -5
  26. data/spec/models/kithe/asset/set_shrine_uploader_spec.rb +39 -0
  27. data/spec/models/kithe/asset_spec.rb +9 -59
  28. data/spec/models/kithe/model_spec.rb +0 -32
  29. data/spec/shrine/kithe_accept_remote_url_spec.rb +49 -0
  30. data/spec/shrine/kithe_checksum_signatures_spec.rb +63 -0
  31. data/spec/shrine/kithe_derivative_definitions_spec.rb +303 -0
  32. data/spec/shrine/kithe_persisted_derivatives_spec.rb +424 -0
  33. data/spec/shrine/kithe_storage_location_spec.rb +43 -15
  34. data/spec/spec_helper.rb +7 -6
  35. data/spec/test_support/images/3x3_pixel.jpg +0 -0
  36. data/spec/test_support/shrine_spec_support.rb +2 -1
  37. metadata +23 -23
  38. data/app/models/kithe/asset/derivative_updater.rb +0 -119
  39. data/app/models/kithe/derivative.rb +0 -15
  40. data/app/uploaders/kithe/derivative_uploader.rb +0 -48
  41. data/spec/models/kithe/asset/asset_create_derivatives_spec.rb +0 -320
  42. data/spec/models/kithe/derivative_spec.rb +0 -168
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '087115597d14a7b5ac33827a00f62fb37a37d7186deea82f3d6204e09a77d0b4'
4
- data.tar.gz: a5f87fdf80a1f521999fcb5a039bcd28831e1427f71e2590729327bac356f148
3
+ metadata.gz: cfaa6ce3c41abdc0779014cb028d3ae7acbbfee6124eb24abca06f52e6f60c30
4
+ data.tar.gz: 4f3951e52b4175c86933870933fd38c0c84dfcf11a5ad8cd18f1eb8c479305b0
5
5
  SHA512:
6
- metadata.gz: 57c51b54e947477b1f69426caa6adc9beb37ea72c25f6210874e2e1837c4ad0a98ad4d43322ee5fddfa2c6e7fb2f311b01c05f9d58435785a3774180225bf23c
7
- data.tar.gz: 1ed33f2a15c07ce47959e21345694815820ed8daa11cf04c8cfdfa9fb274f95ecc56cf326a87c07112adc765f04bd55970ab54efea7f8e44b8a14ca2f8508393
6
+ metadata.gz: 6fe1836bde7b33a29d95324afe745ceeecb59ca95c8952775cce39dd8233c8daf171da971cc4a7bb2691e8dad2b91d50766c9232e3dce5b333da6f14d2f8d6bd
7
+ data.tar.gz: de9bcd5fc0c22c18d9dde7ea9ec1bdc708e08035ee0f5d208131628d6d37bbc61574ae213b0ef69e6161c1fbdf334aad545c734614e10cee8f63f96666ed86dc
@@ -1,7 +1,7 @@
1
1
  module Kithe
2
2
  class CreateDerivativesJob < Job
3
- def perform(asset, mark_created: nil)
4
- asset.create_derivatives(mark_created: mark_created)
3
+ def perform(asset)
4
+ asset.create_derivatives
5
5
  end
6
6
  # This error typically occurs when several large assets, whose derivatives
7
7
  # take a long time to generate, are deleted immediately after ingest.
@@ -1,5 +1,5 @@
1
1
  class Kithe::Asset < Kithe::Model
2
- has_many :derivatives, foreign_key: "asset_id", inverse_of: "asset", dependent: :destroy # dependent destroy to get shrine destroy logic for assets
2
+ include Kithe::Asset::SetShrineUploader
3
3
 
4
4
  # These associations exist for hetereogenous eager-loading, but hide em.
5
5
  # They are defined as self-pointing below.
@@ -26,15 +26,12 @@ class Kithe::Asset < Kithe::Model
26
26
  :md5, :sha1, :sha512,
27
27
  to: :file, allow_nil: true
28
28
  delegate :stored?, to: :file_attacher
29
- delegate :set_promotion_directives, to: :file_attacher
29
+ delegate :set_promotion_directives, :promotion_directives, to: :file_attacher
30
30
 
31
- after_save :remove_invalid_derivatives
32
31
 
33
- # will be sent to file_attacher.promotion_directives=, provided by our
32
+ # will be sent to file_attacher.set_promotion_directives, provided by our
34
33
  # kithe_promotion_hooks shrine plugin.
35
- class_attribute :promotion_directives, instance_writer: false, default: {}
36
-
37
- class_attribute :derivative_definitions, instance_writer: false, default: []
34
+ class_attribute :promotion_directives, instance_accessor: false, default: {}
38
35
 
39
36
  # Callbacks are called by our kiteh_promotion_callbacks shrine plugin, around
40
37
  # shrine promotion. A before callback can cancel promotion with the usual
@@ -45,112 +42,94 @@ class Kithe::Asset < Kithe::Model
45
42
  before_promotion :refresh_metadata_before_promotion
46
43
  after_promotion :schedule_derivatives
47
44
 
48
-
49
-
50
- # Establish a derivative definition that will be used to create a derivative
51
- # when #create_derivatives is called, for instance automatically after promotion.
45
+ # A convenience to call file_attacher.create_persisted_derivatives (from :kithe_derivatives)
46
+ # to create derivatives with conncurrent access safety, with the :kithe_derivatives
47
+ # processor argument, to create derivatives defined using kithe_derivative_definitions.
52
48
  #
53
- # The most basic definition consists of a derivative key, and a ruby block that
54
- # takes the original file, transforms it, and returns a ruby File or other
55
- # (shrine-compatible) IO-like object. It will usually be done inside a custom Asset
56
- # class definition.
49
+ # This is designed for use with kithe_derivatives processor, and has options only relevant
50
+ # to it, although could be expanded to take a processor argument in the future if needed.
57
51
  #
58
- # class Asset < Kithe::Asset
59
- # define_derivative :thumbnail do |original_file|
60
- # end
61
- # end
52
+ # Create derivatives for every definition added to uploader/attacher with kithe_derivatives
53
+ # `define_derivative`. Ordinarily will create a definition for every definition
54
+ # that has not been marked `default_create: false`.
62
55
  #
63
- # The original_file passed in will be a ruby File object that is already open for reading. If
64
- # you need a local file path for your transformation, just use `original_file.path`.
56
+ # But you can also pass `only` and/or `except` to customize the list of definitions to be created,
57
+ # possibly including some that are `default_create: false`.
65
58
  #
66
- # The return value can be any IO-like object. If it is a ruby File or Tempfile,
67
- # that temporary file will be deleted for you after the derivative has been created. If you
68
- # have to make any intermediate files, you are responsible for cleaning them up. Ruby stdlib
69
- # Tempfile and Dir.mktmpdir may be useful.
59
+ # create_derivatives should be idempotent. If it has failed having only created some derivatives,
60
+ # you can always just run it again.
70
61
  #
71
- # If in order to do your transformation you need additional information about the original,
72
- # just add a `record:` keyword argument to your block, and the Asset object will be passed in:
62
+ # Will normally re-create derivatives (per existing definitions) even if they already exist,
63
+ # but pass `lazy: false` to skip creating if a derivative with a given key already exists.
64
+ # This will use the asset `derivatives` association, so if you are doing this in bulk for several
65
+ # assets, you should eager-load the derivatives association for efficiency.
73
66
  #
74
- # define_derivative :thumbnail do |original_file, record:|
75
- # record.width, record.height, record.content_type # etc
76
- # end
67
+ # ## Avoiding eager-download
77
68
  #
78
- # Derivatives are normally uploaded to the Shrine storage labeled :kithe_derivatives,
79
- # but a definition can specify an alternate Shrine storage id. (specified shrine storage key
80
- # is applied on derivative creation; if you change it with existing derivatives, they should
81
- # remain, and be accessible, where they were created; there is no built-in solution at present
82
- # for moving them).
69
+ # Additionally, this has a feature to 'trick' shrine into not eager downloading
70
+ # the original before our kithe_derivatives processor has a chance to decide if it
71
+ # needs to create any derivatives (based on `lazy` arg), making no-op
72
+ # create_derivatives so much faster and more efficient, which matters when doing
73
+ # bulk operations say with our rake task.
83
74
  #
84
- # define_derivative :thumbnail, storage_key: :my_thumb_storage do |original| # ...
75
+ # kithe_derivatives processor must then do a Shrine.with_file to make sure
76
+ # it's a local file, when needed.
85
77
  #
86
- # You can also set `default_create: false` if you want a particular definition not to be
87
- # included in a no-arg `asset.create_derivatives` that is normally triggered on asset creation.
78
+ # See https://github.com/shrinerb/shrine/issues/470
88
79
  #
89
- # And you can set content_type to either a specific type like `image/jpeg` (or array of such) or a general type
90
- # like `image`, if you want to define a derivative generation routine for only certain types.
91
- # If multiple blocks for the same key are defined, with different content_type restrictions,
92
- # the most specific one will be used. That is, for a JPG, `image/jpeg` beats `image` beats no restriction.
93
- def self.define_derivative(key, storage_key: :kithe_derivatives, content_type: nil, default_create: true, &block)
94
- # Make sure we dup the array to handle sub-classes on class_attribute
95
- self.derivative_definitions = self.derivative_definitions.dup.push(
96
- DerivativeDefinition.new(
97
- key: key,
98
- storage_key: storage_key,
99
- content_type: content_type,
100
- default_create: default_create,
101
- proc: block
102
- )
103
- )
104
- end
80
+ def create_derivatives(only: nil, except: nil, lazy: false)
81
+ source = file
82
+ return false unless source
105
83
 
106
- # Returns all derivative keys with a definition, as array of strings
107
- def self.defined_derivative_keys
108
- self.derivative_definitions.collect(&:key).uniq.collect(&:to_s)
109
- end
84
+ #local_files = file_attacher.process_derivatives(:kithe_derivatives, only: only, except: except, lazy: lazy)
85
+ local_files = _process_kithe_derivatives_without_download(source, only: only, except: except, lazy: lazy)
110
86
 
111
- # If you have a subclass that has inherited derivative definitions, you can
112
- # remove them -- only by key, will remove any definitions with that key regardless
113
- # of content_type restrictions.
114
- #
115
- # This could be considered rather bad OO design, you might want to consider
116
- # a different class hieararchy where you don't have to do this. But it's here.
117
- def self.remove_derivative_definition!(*keys)
118
- keys = keys.collect(&:to_sym)
119
- self.derivative_definitions = self.derivative_definitions.reject do |defn|
120
- keys.include?(defn.key.to_sym)
121
- end
87
+ file_attacher.add_persisted_derivatives(local_files)
122
88
  end
123
89
 
124
- # Create derivatives for every definition added with `define_derivative. Ordinarily
125
- # will create a definition for every definition that has not been marked `default_create: false`.
90
+ # Working around Shrine's insistence on pre-downloading original before calling derivative processor.
91
+ # We want to avoid that, so when our `lazy` argument is in use, original does not get eagerly downloaded,
92
+ # but only gets downloaded if needed to make derivatives.
126
93
  #
127
- # But you can also pass `only` and/or `except` to customize the list of definitions to be created,
128
- # possibly including some that are `default_create: false`.
94
+ # This is a somewhat hacky way to do that, loking at the internals of shrine `process_derivatives`,
95
+ # and pulling them out to skip the parts we don't want. We also lose shrine instrumentation
96
+ # around this action.
129
97
  #
130
- # create_derivatives should be idempotent. If it has failed having only created some derivatives,
131
- # you can always just run it again.
98
+ # See: https://github.com/shrinerb/shrine/issues/470
132
99
  #
133
- # Will normally re-create derivatives (per existing definitions) even if they already exist,
134
- # but pass `lazy: false` to skip creating if a derivative with a given key already exists.
135
- # This will use the asset `derivatives` association, so if you are doing this in bulk for several
136
- # assets, you should eager-load the derivatives association for efficiency.
137
- def create_derivatives(only: nil, except: nil, lazy: false, mark_created: nil)
138
- DerivativeCreator.new(derivative_definitions, self, only: only, except: except, lazy: lazy, mark_created: mark_created).call
100
+ # If that were resolved, the 'ordinary' shrine thing would be to replace calls
101
+ # to this local private method with:
102
+ #
103
+ # file_attacher.process_derivatives(:kithe_derivatives, only: only, except: except, lazy: lazy)
104
+ #
105
+ private def _process_kithe_derivatives_without_download(source, **options)
106
+ processor = file_attacher.class.derivatives_processor(:kithe_derivatives)
107
+ local_files = file_attacher.instance_exec(source, **options, &processor)
139
108
  end
140
109
 
141
- # Adds an associated derivative with key and io bytestream specified.
110
+ # Just a convennience for file_attacher.add_persisted_derivatives (from :kithe_derivatives),
111
+ # feel free to use that if you want to add more than one etc. By default stores to
112
+ # :kithe_derivatives, just as `add_persisted_derivatives` does.
113
+ #
114
+ # Note that just like shrine's own usual `add_derivative(s)`, it assumes any files
115
+ # you pass it are meant to be temporary and will delete them, unless you pass
116
+ # `delete: false`.
117
+ #
118
+ # Adds an associated derivative with key and io bytestream specified,
119
+ # doing so in a way that is safe from race conditions under multi-process
120
+ # concurrency.
121
+ #
142
122
  # Normally you don't use this with derivatives defined with `define_derivative`,
143
123
  # this is used by higher-level API. But if you'd like to add a derivative not defined
144
124
  # with `define_derivative`, or for any other reason would like to manually add
145
- # a derivative, this is public API meant for that.
125
+ # a derivative.
146
126
  #
147
- # Ensures safe from race conditions under multi-thread/process concurrency, to
148
- # make sure any existing derivative with same key is atomically replaced,
149
- # and if the asset#file is changed to a different bytestream (compared to what's in memory
150
- # for this asset), we don't end up saving a derivative based on old one.
127
+ # Can specify any options normally allowed for kithe `add_persisted_derivatives`,
128
+ # which are also generally any allowed for shrine `add_derivative`.
151
129
  #
152
- # Can specify any metadata values to be force set on the Derivative#file, and
153
- # a specific Shrine storage key (defaults to :kithe_derivatives shrine storage)
130
+ # asset.update_derivative("big_thumb", File.open(something))
131
+ # asset.update_derivative("something", File.open(something), delete: false)
132
+ # asset.update_derivative("something", File.open(something), storage_key: :registered_storage, metadata: { "foo": "bar" })
154
133
  #
155
134
  # @param key derivative-type identifying key
156
135
  # @param io An IO-like object (according to Shrine), bytestream for the derivative
@@ -158,30 +137,20 @@ class Kithe::Asset < Kithe::Model
158
137
  # @param metadata an optional hash of key/values to set as default metadata for the Derivative#file
159
138
  # shrine object.
160
139
  #
161
- # @return [Derivative] the Derivative created, or nil if it was not created because no longer
140
+ # @return [Shrine::UploadedFile] the Derivative created, or false if it was not created because no longer
162
141
  # applicable (underlying Asset#file has changed in db)
163
- def update_derivative(key, io, storage_key: :kithe_derivatives, metadata: {})
164
- DerivativeUpdater.new(self, key, io, storage_key: storage_key, metadata: metadata).update.tap do |result|
165
- self.derivatives.reset if result
166
- end
142
+ def update_derivative(key, io, **options)
143
+ result = update_derivatives({ key => io }, **options)
144
+ result && result.values.first
167
145
  end
168
146
 
169
- def remove_derivative(key)
170
- if association(:derivatives).loaded?
171
- derivatives.find_all { |d| d.key == key.to_s }.each do |deriv|
172
- derivatives.delete(deriv)
173
- end
174
- else
175
- Kithe::Derivative.where(key: key.to_s, asset: self).each do |deriv|
176
- deriv.destroy!
177
- end
178
- end
147
+ def update_derivatives(deriv_hash, **options)
148
+ file_attacher.add_persisted_derivatives(deriv_hash, **options)
179
149
  end
180
150
 
181
- # Just finds the Derivative object matching supplied key. if you're going to be calling
182
- # this on a list of Asset objects, make sure to preload :derivatives association.
183
- def derivative_for(key)
184
- derivatives.find {|d| d.key == key.to_s }
151
+ # just a convenience for kithe remove_persisted_derivatives
152
+ def remove_derivatives(*keys)
153
+ file_attacher.remove_persisted_derivatives(*keys)
185
154
  end
186
155
 
187
156
  # Runs the shrine promotion step, that we normally have in backgrounding, manually
@@ -205,41 +174,6 @@ class Kithe::Asset < Kithe::Model
205
174
  file_attacher.atomic_promote(**context)
206
175
  end
207
176
 
208
- # The derivative creator sets metadata when it's created all derivatives
209
- # defined as `default_create`. So we can tell you if it's done or not.
210
- def derivatives_created?
211
- if file
212
- !!file.metadata["derivatives_created"]
213
- end
214
- end
215
-
216
- # Take out a DB lock on the asset with unchanged sha512 saved in metadata. If a lock
217
- # can't be acquired -- which would be expected to be because the asset has already changed
218
- # and has a new sha for some reason -- returns nil.
219
- #
220
- # Useful for making a change to an asset making sure it applies to a certain original file.
221
- #
222
- # Needs to be done in a transaction, and you should keep the transaction SMALL AS POSSIBLE.
223
- # We can't check to make sure you're in a transaction reliably because of Rails transactional
224
- # tests, you gotta do it!
225
- #
226
- # This method is mostly intended for internal Kithe use, cause it's a bit tricky.
227
- def acquire_lock_on_sha
228
- raise ArgumentError.new("Can't acquire lock without sha512 in metadata") if self.sha512.blank?
229
-
230
- Kithe::Asset.where(id: self.id).where("file_data -> 'metadata' ->> 'sha512' = ?", self.sha512).lock.first
231
- end
232
-
233
- # Intentionally only true if there WAS a sha512 before AND it's changed.
234
- # Allowing false on nil previous sha512 allows certain conditions, mostly only
235
- # in testing, where you want to assign a derivative to not-yet-promoted file.
236
- def saved_change_to_file_sha?
237
- saved_change_to_file_data? &&
238
- saved_change_to_file_data.first.try(:dig, "metadata", "sha512") != nil &&
239
- saved_change_to_file_data.first.try(:dig, "metadata", "sha512") !=
240
- saved_change_to_file_data.second.try(:dig, "metadata", "sha512")
241
- end
242
-
243
177
  # An Asset is it's own representative
244
178
  def representative
245
179
  self
@@ -252,8 +186,10 @@ class Kithe::Asset < Kithe::Model
252
186
 
253
187
  def initialize(*args)
254
188
  super
255
- if promotion_directives.present?
256
- file_attacher.set_promotion_directives(promotion_directives)
189
+
190
+ # copy class-level global promotion directives as initial instance value
191
+ if self.class.promotion_directives.present?
192
+ self.set_promotion_directives(self.class.promotion_directives)
257
193
  end
258
194
  end
259
195
 
@@ -261,7 +197,7 @@ class Kithe::Asset < Kithe::Model
261
197
 
262
198
  # called by after_promotion hook
263
199
  def schedule_derivatives
264
- return unless self.derivative_definitions.present? # no need to schedule if we don't have any
200
+ return unless self.file_attacher.kithe_derivative_definitions.present? # no need to schedule if we don't have any
265
201
 
266
202
  Kithe::TimingPromotionDirective.new(key: :create_derivatives, directives: file_attacher.promotion_directives) do |directive|
267
203
  if directive.inline?
@@ -276,12 +212,4 @@ class Kithe::Asset < Kithe::Model
276
212
  def refresh_metadata_before_promotion
277
213
  file.refresh_metadata!(promoting: true)
278
214
  end
279
-
280
- # Meant to be called in after_save hook, looks at activerecord dirty tracking in order
281
- # to removes all derivatives if the asset sha512 has changed
282
- def remove_invalid_derivatives
283
- if saved_change_to_file_sha?
284
- derivatives.destroy_all
285
- end
286
- end
287
215
  end
@@ -1,6 +1,6 @@
1
1
  # Creates derivatives from definitions stored on an Asset class
2
2
  class Kithe::Asset::DerivativeCreator
3
- attr_reader :definitions, :asset, :only, :except, :lazy, :mark_created
3
+ attr_reader :definitions, :shrine_attacher, :only, :except, :lazy, :source_io
4
4
 
5
5
  # A helper class that provides the implementation for Kithe::Asset#create_derivatives,
6
6
  # normally only expected to be called from there.
@@ -13,57 +13,62 @@ class Kithe::Asset::DerivativeCreator
13
13
  # (deleted) if it is a File or Tempfile object.
14
14
  #
15
15
  # @param definitions an array of DerivativeDefinition
16
- # @param asset an Asset instance
16
+ # @param shrine_attacher a shrine attacher instance holding attachment state from an individual
17
+ # model, from eg `asset.file_attacher`
17
18
  # @param only array of definition keys, only execute these (doesn't matter if they are `default_create` or not)
18
19
  # @param except array of definition keys, exclude these from definitions of derivs to be created
19
20
  # @param lazy (default false), Normally we will create derivatives for all applicable definitions,
20
21
  # overwriting any that already exist for a given key. If the definition has changed, a new
21
22
  # derivative created with new definition will overwrite existing. However, if you pass lazy false,
22
23
  # it'll skip derivative creation if the derivative already exists, which can save time
23
- # if you are only intending to create missing derivatives. With lazy:false, the asset
24
- # derivatives association will be consulted, so should be eager-loaded if you are going
25
- # to be calling on multiple assets.
26
- # @param mark_created [Boolean] if true will set shrine metadata indicating we've done
27
- # derivative creation phase, so Asset#derivatives_created? will return true. Defaults to nil,
28
- # meaning true if and only if `only` is nil -- mark created if creating default derivatives.
29
- def initialize(definitions, asset, only:nil, except:nil, lazy: false, mark_created: :not_set)
24
+ # if you are only intending to create missing derivatives.
25
+ def initialize(definitions, source_io:, shrine_attacher:, only:nil, except:nil, lazy: false)
30
26
  @definitions = definitions
31
- @asset = asset
32
- @only = only && Array(only)
33
- @except = except && Array(except)
27
+ @source_io = source_io
28
+ @shrine_attacher = shrine_attacher
29
+ @only = only && Array(only).collect(&:to_sym)
30
+ @except = except && Array(except).collect(&:to_sym)
34
31
  @lazy = !!lazy
35
- @mark_created = mark_created.nil? ? (only.nil? && except.nil?) : !! mark_created
32
+
33
+ unless shrine_attacher.kind_of?(Shrine::Attacher)
34
+ raise ArgumentError.new("expect second arg Shrine::Attacher not #{shrine_attacher.class}")
35
+ end
36
36
  end
37
37
 
38
38
  def call
39
- return unless asset.file.present? # if no file, can't create derivatives
39
+ return unless shrine_attacher.file.present? # if no file, can't create derivatives
40
40
 
41
41
  definitions_to_create = applicable_definitions
42
+
42
43
  if lazy
43
- existing_derivative_keys = asset.derivatives.collect(&:key).collect(&:to_s)
44
+ existing_derivative_keys = shrine_attacher.derivatives.keys
44
45
  definitions_to_create.reject! do |defn|
45
- existing_derivative_keys.include?(defn.key.to_s)
46
+ existing_derivative_keys.include?(defn.key)
46
47
  end
47
48
  end
48
49
 
49
- return unless definitions_to_create.present?
50
+ return {} unless definitions_to_create.present?
51
+
52
+ derivatives = {}
50
53
 
51
- # Note, MAY make a superfluous copy and/or download of original file, ongoing
52
- # discussion https://github.com/shrinerb/shrine/pull/329#issuecomment-443615868
53
- # https://github.com/shrinerb/shrine/pull/332
54
- Shrine.with_file(asset.file) do |original_file|
54
+ # Make sure we have this as a local file, because many processors
55
+ # require it, for instance for shelling out to command line.
56
+ # This might trigger a download, but note we are only doing it if we have
57
+ # `definitions_to_create`, otherwise we already returned.
58
+ shrine_attacher.shrine_class.with_file(source_io) do |source_io_as_file|
55
59
  definitions_to_create.each do |defn|
56
- deriv_bytestream = defn.call(original_file: original_file, record: asset)
60
+ deriv_bytestream = defn.call(original_file: source_io_as_file, attacher: shrine_attacher)
57
61
 
58
62
  if deriv_bytestream
59
- asset.update_derivative(defn.key, deriv_bytestream, storage_key: defn.storage_key)
60
- cleanup_returned_io(deriv_bytestream)
63
+ derivatives[defn.key] = deriv_bytestream
61
64
  end
62
65
 
63
- original_file.rewind
66
+ # may not need this but it doesn't hurt...
67
+ source_io.rewind
64
68
  end
65
- mark_derivatives_created! if mark_created
66
69
  end
70
+
71
+ derivatives
67
72
  end
68
73
 
69
74
  private
@@ -83,7 +88,7 @@ class Kithe::Asset::DerivativeCreator
83
88
  candidates = definitions.find_all do |defn|
84
89
  (only.nil? ? defn.default_create : only.include?(defn.key)) &&
85
90
  (except.nil? || ! except.include?(defn.key)) &&
86
- defn.applies_to?(asset)
91
+ defn.applies_to_content_type?(shrine_attacher.file.content_type)
87
92
  end
88
93
 
89
94
  # Now we gotta filter out any duplicate keys based on our priority rules, but keep
@@ -107,39 +112,4 @@ class Kithe::Asset::DerivativeCreator
107
112
  # Now we uniq keeping last defn
108
113
  candidates.reverse.uniq {|d| d.key }.reverse
109
114
  end
110
-
111
- def cleanup_returned_io(io)
112
- if io.respond_to?(:close!)
113
- # it's a Tempfile, clean it up now
114
- io.close!
115
- elsif io.is_a?(File)
116
- # It's a File, close it and delete it.
117
- io.close
118
- File.unlink(io.path)
119
- end
120
- end
121
-
122
- # Sets kithe asset metadata "derivatives_created" to `true`, so
123
- # code can know that we're finished creating all `default_create`
124
- # derivatives.
125
- #
126
- # Uses a db-level atomic jsonb update and db-locking to make sure it can do this
127
- # without overwriting any other metadata changes, safely.
128
- def mark_derivatives_created!
129
- asset.transaction do
130
- unless asset.acquire_lock_on_sha
131
- # asset bytestream has changed
132
- return nil
133
- end
134
-
135
- sql = <<~SQL
136
- UPDATE "#{Kithe::Asset.table_name}"
137
- SET file_data = jsonb_set(file_data, '{metadata, derivatives_created}', 'true')
138
- WHERE id = '#{asset.id}'
139
- SQL
140
-
141
- #ActiveRecord::Base.connection.exec_update("update table set f1=#{ActiveRecord::Base.sanitize(f1)}")
142
- Kithe::Asset.connection.execute(sql)
143
- end
144
- end
145
115
  end