carrierwave 0.11.2 → 3.1.2

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 (69) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +495 -173
  3. data/lib/carrierwave/compatibility/paperclip.rb +4 -4
  4. data/lib/carrierwave/downloader/base.rb +101 -0
  5. data/lib/carrierwave/downloader/remote_file.rb +68 -0
  6. data/lib/carrierwave/error.rb +1 -0
  7. data/lib/carrierwave/locale/en.yml +11 -5
  8. data/lib/carrierwave/mount.rb +217 -182
  9. data/lib/carrierwave/mounter.rb +257 -0
  10. data/lib/carrierwave/orm/activerecord.rb +29 -35
  11. data/lib/carrierwave/processing/mini_magick.rb +169 -84
  12. data/lib/carrierwave/processing/rmagick.rb +107 -25
  13. data/lib/carrierwave/processing/vips.rb +315 -0
  14. data/lib/carrierwave/processing.rb +1 -1
  15. data/lib/carrierwave/sanitized_file.rb +105 -87
  16. data/lib/carrierwave/storage/abstract.rb +16 -3
  17. data/lib/carrierwave/storage/file.rb +71 -3
  18. data/lib/carrierwave/storage/fog.rb +228 -57
  19. data/lib/carrierwave/storage.rb +1 -9
  20. data/lib/carrierwave/test/matchers.rb +88 -19
  21. data/lib/carrierwave/uploader/cache.rb +75 -45
  22. data/lib/carrierwave/uploader/callbacks.rb +1 -3
  23. data/lib/carrierwave/uploader/configuration.rb +84 -16
  24. data/lib/carrierwave/uploader/content_type_allowlist.rb +62 -0
  25. data/lib/carrierwave/uploader/content_type_denylist.rb +62 -0
  26. data/lib/carrierwave/uploader/default_url.rb +3 -5
  27. data/lib/carrierwave/uploader/dimension.rb +66 -0
  28. data/lib/carrierwave/uploader/download.rb +4 -74
  29. data/lib/carrierwave/uploader/extension_allowlist.rb +63 -0
  30. data/lib/carrierwave/uploader/extension_denylist.rb +64 -0
  31. data/lib/carrierwave/uploader/file_size.rb +43 -0
  32. data/lib/carrierwave/uploader/mountable.rb +13 -8
  33. data/lib/carrierwave/uploader/processing.rb +51 -13
  34. data/lib/carrierwave/uploader/proxy.rb +20 -9
  35. data/lib/carrierwave/uploader/remove.rb +0 -2
  36. data/lib/carrierwave/uploader/serialization.rb +2 -4
  37. data/lib/carrierwave/uploader/store.rb +85 -28
  38. data/lib/carrierwave/uploader/url.rb +8 -7
  39. data/lib/carrierwave/uploader/versions.rb +175 -125
  40. data/lib/carrierwave/uploader.rb +12 -10
  41. data/lib/carrierwave/utilities/file_name.rb +47 -0
  42. data/lib/carrierwave/utilities/uri.rb +14 -12
  43. data/lib/carrierwave/utilities.rb +1 -3
  44. data/lib/carrierwave/validations/active_model.rb +7 -11
  45. data/lib/carrierwave/version.rb +1 -1
  46. data/lib/carrierwave.rb +48 -21
  47. data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +8 -11
  48. data/lib/generators/uploader_generator.rb +3 -3
  49. metadata +124 -86
  50. data/lib/carrierwave/locale/cs.yml +0 -11
  51. data/lib/carrierwave/locale/de.yml +0 -11
  52. data/lib/carrierwave/locale/el.yml +0 -11
  53. data/lib/carrierwave/locale/es.yml +0 -11
  54. data/lib/carrierwave/locale/fr.yml +0 -11
  55. data/lib/carrierwave/locale/ja.yml +0 -11
  56. data/lib/carrierwave/locale/nb.yml +0 -11
  57. data/lib/carrierwave/locale/nl.yml +0 -11
  58. data/lib/carrierwave/locale/pl.yml +0 -11
  59. data/lib/carrierwave/locale/pt-BR.yml +0 -11
  60. data/lib/carrierwave/locale/pt-PT.yml +0 -11
  61. data/lib/carrierwave/locale/ru.yml +0 -11
  62. data/lib/carrierwave/locale/sk.yml +0 -11
  63. data/lib/carrierwave/locale/tr.yml +0 -11
  64. data/lib/carrierwave/processing/mime_types.rb +0 -74
  65. data/lib/carrierwave/uploader/content_type_blacklist.rb +0 -48
  66. data/lib/carrierwave/uploader/content_type_whitelist.rb +0 -48
  67. data/lib/carrierwave/uploader/extension_blacklist.rb +0 -47
  68. data/lib/carrierwave/uploader/extension_whitelist.rb +0 -49
  69. data/lib/carrierwave/utilities/deprecation.rb +0 -18
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module CarrierWave
4
2
  module Storage
5
3
 
@@ -9,13 +7,17 @@ module CarrierWave
9
7
  # pretty much it.
10
8
  #
11
9
  class File < Abstract
10
+ def initialize(*)
11
+ super
12
+ @cache_called = nil
13
+ end
12
14
 
13
15
  ##
14
16
  # Move the file to the uploader's store path.
15
17
  #
16
18
  # By default, store!() uses copy_to(), which operates by copying the file
17
19
  # from the cache to the store, then deleting the file from the cache.
18
- # If move_to_store() is overriden to return true, then store!() uses move_to(),
20
+ # If move_to_store() is overridden to return true, then store!() uses move_to(),
19
21
  # which simply moves the file from cache to store. Useful for large files.
20
22
  #
21
23
  # === Parameters
@@ -51,6 +53,72 @@ module CarrierWave
51
53
  CarrierWave::SanitizedFile.new(path)
52
54
  end
53
55
 
56
+ ##
57
+ # Stores given file to cache directory.
58
+ #
59
+ # === Parameters
60
+ #
61
+ # [new_file (File, IOString, Tempfile)] any kind of file object
62
+ #
63
+ # === Returns
64
+ #
65
+ # [CarrierWave::SanitizedFile] a sanitized file
66
+ #
67
+ def cache!(new_file)
68
+ new_file.move_to(::File.expand_path(uploader.cache_path, uploader.root), uploader.permissions, uploader.directory_permissions, true)
69
+ rescue Errno::EMLINK, Errno::ENOSPC => e
70
+ raise(e) if @cache_called
71
+ @cache_called = true
72
+
73
+ # NOTE: Remove cached files older than 10 minutes
74
+ clean_cache!(600)
75
+
76
+ cache!(new_file)
77
+ end
78
+
79
+ ##
80
+ # Retrieves the file with the given cache_name from the cache.
81
+ #
82
+ # === Parameters
83
+ #
84
+ # [cache_name (String)] uniquely identifies a cache file
85
+ #
86
+ # === Raises
87
+ #
88
+ # [CarrierWave::InvalidParameter] if the cache_name is incorrectly formatted.
89
+ #
90
+ def retrieve_from_cache!(identifier)
91
+ CarrierWave::SanitizedFile.new(::File.expand_path(uploader.cache_path(identifier), uploader.root))
92
+ end
93
+
94
+ ##
95
+ # Deletes a cache dir
96
+ #
97
+ def delete_dir!(path)
98
+ if path
99
+ begin
100
+ Dir.rmdir(::File.expand_path(path, uploader.root))
101
+ rescue Errno::ENOENT
102
+ # Ignore: path does not exist
103
+ rescue Errno::ENOTDIR
104
+ # Ignore: path is not a dir
105
+ rescue Errno::ENOTEMPTY, Errno::EEXIST
106
+ # Ignore: dir is not empty
107
+ end
108
+ end
109
+ end
110
+
111
+ def clean_cache!(seconds)
112
+ Dir.glob(::File.expand_path(::File.join(uploader.cache_dir, '*'), uploader.root)).each do |dir|
113
+ # generate_cache_id returns key formatted TIMEINT-PID(-COUNTER)-RND
114
+ matched = dir.scan(/(\d+)-\d+-\d+(?:-\d+)?/).first
115
+ next unless matched
116
+ time = Time.at(matched[0].to_i)
117
+ if time < (Time.now.utc - seconds)
118
+ FileUtils.rm_rf(dir)
119
+ end
120
+ end
121
+ end
54
122
  end # File
55
123
  end # Storage
56
124
  end # CarrierWave
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module CarrierWave
4
2
  module Storage
5
3
 
@@ -18,6 +16,10 @@ module CarrierWave
18
16
  # [:fog_authenticated_url_expiration] (optional) time (in seconds) that authenticated urls
19
17
  # will be valid, when fog_public is false and provider is AWS or Google, defaults to 600
20
18
  # [:fog_use_ssl_for_aws] (optional) #public_url will use https for the AWS generated URL]
19
+ # [:fog_aws_accelerate] (optional) #public_url will use s3-accelerate subdomain
20
+ # instead of s3, defaults to false
21
+ # [:fog_aws_fips] (optional) #public_url will use s3-fips subdomain
22
+ # instead of s3, defaults to false
21
23
  #
22
24
  #
23
25
  # AWS credentials contain the following keys:
@@ -25,12 +27,12 @@ module CarrierWave
25
27
  # [:aws_access_key_id]
26
28
  # [:aws_secret_access_key]
27
29
  # [:region] (optional) defaults to 'us-east-1'
28
- # :region should be one of ['eu-west-1', 'us-east-1', 'ap-southeast-1', 'us-west-1', 'ap-northeast-1']
30
+ # :region should be one of ['eu-west-1', 'us-east-1', 'ap-southeast-1', 'us-west-1', 'ap-northeast-1', 'eu-central-1']
29
31
  #
30
32
  #
31
33
  # Google credentials contain the following keys:
32
34
  # [:google_storage_access_key_id]
33
- # [:google_storage_secrete_access_key]
35
+ # [:google_storage_secret_access_key]
34
36
  #
35
37
  #
36
38
  # Local credentials contain the following keys:
@@ -60,6 +62,14 @@ module CarrierWave
60
62
  def connection_cache
61
63
  @connection_cache ||= {}
62
64
  end
65
+
66
+ def eager_load
67
+ # see #1198. This will hopefully no longer be necessary in future release of fog
68
+ fog_credentials = CarrierWave::Uploader::Base.fog_credentials
69
+ if fog_credentials.present?
70
+ CarrierWave::Storage::Fog.connection_cache[fog_credentials] ||= ::Fog::Storage.new(fog_credentials)
71
+ end
72
+ end
63
73
  end
64
74
 
65
75
  ##
@@ -94,6 +104,58 @@ module CarrierWave
94
104
  CarrierWave::Storage::Fog::File.new(uploader, self, uploader.store_path(identifier))
95
105
  end
96
106
 
107
+ ##
108
+ # Stores given file to cache directory.
109
+ #
110
+ # === Parameters
111
+ #
112
+ # [new_file (File, IOString, Tempfile)] any kind of file object
113
+ #
114
+ # === Returns
115
+ #
116
+ # [CarrierWave::SanitizedFile] a sanitized file
117
+ #
118
+ def cache!(new_file)
119
+ f = CarrierWave::Storage::Fog::File.new(uploader, self, uploader.cache_path)
120
+ f.store(new_file)
121
+ f
122
+ end
123
+
124
+ ##
125
+ # Retrieves the file with the given cache_name from the cache.
126
+ #
127
+ # === Parameters
128
+ #
129
+ # [cache_name (String)] uniquely identifies a cache file
130
+ #
131
+ # === Raises
132
+ #
133
+ # [CarrierWave::InvalidParameter] if the cache_name is incorrectly formatted.
134
+ #
135
+ def retrieve_from_cache!(identifier)
136
+ CarrierWave::Storage::Fog::File.new(uploader, self, uploader.cache_path(identifier))
137
+ end
138
+
139
+ ##
140
+ # Deletes a cache dir
141
+ #
142
+ def delete_dir!(path)
143
+ # do nothing, because there's no such things as 'empty directory'
144
+ end
145
+
146
+ def clean_cache!(seconds)
147
+ connection.directories.new(
148
+ :key => uploader.fog_directory,
149
+ :public => uploader.fog_public
150
+ ).files.all(:prefix => uploader.cache_dir).each do |file|
151
+ # generate_cache_id returns key formatted TIMEINT-PID(-COUNTER)-RND
152
+ matched = file.key.match(/(\d+)-\d+-\d+(?:-\d+)?/)
153
+ next unless matched
154
+ time = Time.at(matched[1].to_i)
155
+ file.destroy if time < (Time.now.utc - seconds)
156
+ end
157
+ end
158
+
97
159
  def connection
98
160
  @connection ||= begin
99
161
  options = credentials = uploader.fog_credentials
@@ -102,7 +164,10 @@ module CarrierWave
102
164
  end
103
165
 
104
166
  class File
167
+ DEFAULT_S3_REGION = 'us-east-1'.freeze
168
+
105
169
  include CarrierWave::Utilities::Uri
170
+ include CarrierWave::Utilities::FileName
106
171
 
107
172
  ##
108
173
  # Current local path to file
@@ -126,7 +191,7 @@ module CarrierWave
126
191
 
127
192
  ##
128
193
  # Return a temporary authenticated url to a private file, if available
129
- # Only supported for AWS, Rackspace and Google providers
194
+ # Only supported for AWS, Rackspace, Google, AzureRM and Aliyun providers
130
195
  #
131
196
  # === Returns
132
197
  #
@@ -135,19 +200,28 @@ module CarrierWave
135
200
  # [NilClass] no authenticated url available
136
201
  #
137
202
  def authenticated_url(options = {})
138
- if ['AWS', 'Google', 'Rackspace', 'OpenStack'].include?(@uploader.fog_credentials[:provider])
203
+ if ['AWS', 'Google', 'Rackspace', 'OpenStack', 'AzureRM', 'Aliyun', 'backblaze'].include?(fog_provider)
139
204
  # avoid a get by using local references
140
205
  local_directory = connection.directories.new(:key => @uploader.fog_directory)
141
206
  local_file = local_directory.files.new(:key => path)
142
- if @uploader.fog_credentials[:provider] == "AWS"
143
- local_file.url(::Fog::Time.now + @uploader.fog_authenticated_url_expiration, options)
144
- elsif ['Rackspace', 'OpenStack'].include?(@uploader.fog_credentials[:provider])
145
- connection.get_object_https_url(@uploader.fog_directory, path, ::Fog::Time.now + @uploader.fog_authenticated_url_expiration)
207
+ expire_at = options[:expire_at] || ::Fog::Time.now.since(@uploader.fog_authenticated_url_expiration.to_i)
208
+ case fog_provider
209
+ when 'AWS', 'Google'
210
+ # Older versions of fog-google do not support options as a parameter
211
+ if url_options_supported?(local_file)
212
+ local_file.url(expire_at, options)
213
+ else
214
+ warn "Options hash not supported in #{local_file.class}. You may need to upgrade your Fog provider."
215
+ local_file.url(expire_at)
216
+ end
217
+ when 'Rackspace', 'OpenStack'
218
+ connection.get_object_https_url(@uploader.fog_directory, path, expire_at, options)
219
+ when 'Aliyun'
220
+ expire_at -= Time.now
221
+ local_file.url(expire_at)
146
222
  else
147
- local_file.url(::Fog::Time.now + @uploader.fog_authenticated_url_expiration)
223
+ local_file.url(expire_at)
148
224
  end
149
- else
150
- nil
151
225
  end
152
226
  end
153
227
 
@@ -159,7 +233,7 @@ module CarrierWave
159
233
  # [String] value of content-type
160
234
  #
161
235
  def content_type
162
- @content_type || file.content_type
236
+ @content_type || file.try(:content_type)
163
237
  end
164
238
 
165
239
  ##
@@ -182,19 +256,9 @@ module CarrierWave
182
256
  #
183
257
  def delete
184
258
  # avoid a get by just using local reference
185
- directory.files.new(:key => path).destroy
186
- end
187
-
188
- ##
189
- # Return extension of file
190
- #
191
- # === Returns
192
- #
193
- # [String] extension of file or nil if the file has no extension
194
- #
195
- def extension
196
- path_elements = path.split('.')
197
- path_elements.last if path_elements.size > 1
259
+ directory.files.new(:key => path).destroy.tap do |result|
260
+ @file = nil if result
261
+ end
198
262
  end
199
263
 
200
264
  ##
@@ -213,7 +277,7 @@ module CarrierWave
213
277
  end
214
278
 
215
279
  def initialize(uploader, base, path)
216
- @uploader, @base, @path = uploader, base, path
280
+ @uploader, @base, @path, @content_type = uploader, base, path, nil
217
281
  end
218
282
 
219
283
  ##
@@ -223,6 +287,16 @@ module CarrierWave
223
287
  #
224
288
  # [String] contents of file
225
289
  def read
290
+ file_body = file&.body
291
+
292
+ return if file_body.nil?
293
+ return file_body unless file_body.is_a?(::File)
294
+
295
+ # Fog::Storage::XXX::File#body could return the source file which was uploaded to the remote server.
296
+ return read_source_file if ::File.exist?(file_body.path)
297
+
298
+ # If the source file doesn't exist, the remote content is read
299
+ @file = nil
226
300
  file.body
227
301
  end
228
302
 
@@ -234,7 +308,16 @@ module CarrierWave
234
308
  # [Integer] size of file body
235
309
  #
236
310
  def size
237
- file.content_length
311
+ file.nil? ? 0 : file.content_length
312
+ end
313
+
314
+ ##
315
+ # === Returns
316
+ #
317
+ # [Boolean] whether the file is non-existent or empty
318
+ #
319
+ def empty?
320
+ !exists? || size.zero?
238
321
  end
239
322
 
240
323
  ##
@@ -244,7 +327,7 @@ module CarrierWave
244
327
  #
245
328
  # [Boolean] true if file exists or false
246
329
  def exists?
247
- !!directory.files.head(path)
330
+ !!file
248
331
  end
249
332
 
250
333
  ##
@@ -254,15 +337,19 @@ module CarrierWave
254
337
  #
255
338
  # [Boolean] true on success or raises error
256
339
  def store(new_file)
257
- fog_file = new_file.to_file
258
- @content_type ||= new_file.content_type
259
- @file = directory.files.create({
260
- :body => fog_file ? fog_file : new_file.read,
261
- :content_type => @content_type,
262
- :key => path,
263
- :public => @uploader.fog_public
264
- }.merge(@uploader.fog_attributes))
265
- fog_file.close if fog_file && !fog_file.closed?
340
+ if new_file.is_a?(self.class)
341
+ new_file.copy_to(path)
342
+ else
343
+ fog_file = new_file.to_file
344
+ @content_type ||= new_file.content_type
345
+ @file = directory.files.create({
346
+ :body => fog_file || new_file.read,
347
+ :content_type => @content_type,
348
+ :key => path,
349
+ :public => @uploader.fog_public
350
+ }.merge(@uploader.fog_attributes))
351
+ fog_file.close if fog_file && !fog_file.closed?
352
+ end
266
353
  true
267
354
  end
268
355
 
@@ -277,7 +364,7 @@ module CarrierWave
277
364
  #
278
365
  def public_url
279
366
  encoded_path = encode_path(path)
280
- if host = @uploader.asset_host
367
+ if (host = @uploader.asset_host)
281
368
  if host.respond_to? :call
282
369
  "#{host.call(self)}/#{encoded_path}"
283
370
  else
@@ -285,23 +372,38 @@ module CarrierWave
285
372
  end
286
373
  else
287
374
  # AWS/Google optimized for speed over correctness
288
- case @uploader.fog_credentials[:provider]
375
+ case fog_provider
289
376
  when 'AWS'
290
377
  # check if some endpoint is set in fog_credentials
291
378
  if @uploader.fog_credentials.has_key?(:endpoint)
379
+ raise 'fog_aws_fips = true is incompatible with :endpoint, as FIPS endpoints do not support path-style URLs.' if @uploader.fog_aws_fips
292
380
  "#{@uploader.fog_credentials[:endpoint]}/#{@uploader.fog_directory}/#{encoded_path}"
293
381
  else
294
382
  protocol = @uploader.fog_use_ssl_for_aws ? "https" : "http"
295
- # if directory is a valid subdomain, use that style for access
296
- if @uploader.fog_directory.to_s =~ /^(?:[a-z]|\d(?!\d{0,2}(?:\d{1,3}){3}$))(?:[a-z0-9\.]|(?![\-])|\-(?![\.])){1,61}[a-z0-9]$/
297
- "#{protocol}://#{@uploader.fog_directory}.s3.amazonaws.com/#{encoded_path}"
298
- else
299
- # directory is not a valid subdomain, so use path style for access
300
- "#{protocol}://s3.amazonaws.com/#{@uploader.fog_directory}/#{encoded_path}"
383
+
384
+ subdomain_regex = /^(?:[a-z]|\d(?!\d{0,2}(?:\d{1,3}){3}$))(?:[a-z0-9\.]|(?![\-])|\-(?![\.])){1,61}[a-z0-9]$/
385
+ # To use the virtual-hosted style, the bucket name needs to be representable as a subdomain
386
+ use_virtual_hosted_style = @uploader.fog_directory.to_s =~ subdomain_regex && !(protocol == 'https' && @uploader.fog_directory =~ /\./)
387
+
388
+ region = @uploader.fog_credentials[:region].to_s
389
+ regional_host = 's3.amazonaws.com' # used for DEFAULT_S3_REGION or no region set
390
+ if @uploader.fog_aws_fips
391
+ regional_host = "s3-fips.#{region}.amazonaws.com" # https://aws.amazon.com/compliance/fips/
392
+ elsif ![DEFAULT_S3_REGION, ''].include?(region)
393
+ regional_host = "s3.#{region}.amazonaws.com"
394
+ end
395
+
396
+ if use_virtual_hosted_style
397
+ regional_host = 's3-accelerate.amazonaws.com' if @uploader.fog_aws_accelerate
398
+ "#{protocol}://#{@uploader.fog_directory}.#{regional_host}/#{encoded_path}"
399
+ else # directory is not a valid subdomain, so use path style for access
400
+ raise 'FIPS Endpoints can only be used with Virtual Hosted-Style addressing.' if @uploader.fog_aws_fips
401
+ "#{protocol}://#{regional_host}/#{@uploader.fog_directory}/#{encoded_path}"
301
402
  end
302
403
  end
303
404
  when 'Google'
304
- "https://commondatastorage.googleapis.com/#{@uploader.fog_directory}/#{encoded_path}"
405
+ # https://cloud.google.com/storage/docs/access-public-data
406
+ "https://storage.googleapis.com/#{@uploader.fog_directory}/#{encoded_path}"
305
407
  else
306
408
  # avoid a get by just using local reference
307
409
  directory.files.new(:key => path).public_url
@@ -310,7 +412,7 @@ module CarrierWave
310
412
  end
311
413
 
312
414
  ##
313
- # Return url to file, if avaliable
415
+ # Return url to file, if available
314
416
  #
315
417
  # === Returns
316
418
  #
@@ -336,8 +438,42 @@ module CarrierWave
336
438
  # [NilClass] no file name available
337
439
  #
338
440
  def filename(options = {})
339
- if file_url = url(options)
340
- URI.decode(file_url).gsub(/.*\/(.*?$)/, '\1').split('?').first
441
+ return unless (file_url = url(options))
442
+ CGI.unescape(file_url.split('?').first).gsub(/.*\/(.*?$)/, '\1')
443
+ end
444
+
445
+ ##
446
+ # Creates a copy of this file and returns it.
447
+ #
448
+ # === Parameters
449
+ #
450
+ # [new_path (String)] The path where the file should be copied to.
451
+ #
452
+ # === Returns
453
+ #
454
+ # @return [CarrierWave::Storage::Fog::File] the location where the file will be stored.
455
+ #
456
+ def copy_to(new_path)
457
+ file.copy(@uploader.fog_directory, new_path, copy_options)
458
+ CarrierWave::Storage::Fog::File.new(@uploader, @base, new_path)
459
+ end
460
+
461
+ ##
462
+ # Return the local file
463
+ #
464
+ # === Returns
465
+ #
466
+ # [File] The local file as Ruby's File class
467
+ # or
468
+ # [NilClass] When there's no file, or the file is remotely stored
469
+ #
470
+ def to_file
471
+ return nil unless file.body.is_a? ::File
472
+
473
+ if file.body.closed?
474
+ ::File.open(file.body.path) # Reopen if it's already closed
475
+ else
476
+ file.body
341
477
  end
342
478
  end
343
479
 
@@ -362,12 +498,10 @@ module CarrierWave
362
498
  # [Fog::#{provider}::Directory] containing directory
363
499
  #
364
500
  def directory
365
- @directory ||= begin
366
- connection.directories.new(
367
- :key => @uploader.fog_directory,
368
- :public => @uploader.fog_public
369
- )
370
- end
501
+ @directory ||= connection.directories.new(
502
+ :key => @uploader.fog_directory,
503
+ :public => @uploader.fog_public
504
+ )
371
505
  end
372
506
 
373
507
  ##
@@ -381,6 +515,43 @@ module CarrierWave
381
515
  @file ||= directory.files.head(path)
382
516
  end
383
517
 
518
+ def copy_options
519
+ options = {}
520
+ options.merge!(acl_header) if acl_header.present?
521
+ options[fog_provider == "Google" ? :content_type : 'Content-Type'] ||= content_type if content_type
522
+ options.merge(@uploader.fog_attributes)
523
+ end
524
+
525
+ def acl_header
526
+ case fog_provider
527
+ when 'AWS'
528
+ { 'x-amz-acl' => @uploader.fog_public ? 'public-read' : 'private' }
529
+ when "Google"
530
+ @uploader.fog_public ? { destination_predefined_acl: "publicRead" } : {}
531
+ else
532
+ {}
533
+ end
534
+ end
535
+
536
+ def fog_provider
537
+ @uploader.fog_credentials[:provider].to_s
538
+ end
539
+
540
+ def read_source_file
541
+ source_file = to_file
542
+ return unless source_file
543
+
544
+ begin
545
+ source_file.read
546
+ ensure
547
+ source_file.close
548
+ end
549
+ end
550
+
551
+ def url_options_supported?(local_file)
552
+ parameters = local_file.method(:url).parameters
553
+ parameters.count == 2 && parameters[1].include?(:options)
554
+ end
384
555
  end
385
556
 
386
557
  end # Fog
@@ -1,11 +1,3 @@
1
1
  require "carrierwave/storage/abstract"
2
2
  require "carrierwave/storage/file"
3
-
4
- %w(aws google openstack rackspace).each do |fog_dependency|
5
- begin
6
- require "fog/#{fog_dependency}"
7
- rescue LoadError
8
- end
9
- end
10
-
11
- require "carrierwave/storage/fog" if defined?(Fog)
3
+ require "carrierwave/storage/fog"