zipline 1.4.1 → 1.6.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +0 -1
- data/Gemfile +0 -10
- data/README.md +4 -1
- data/lib/zipline/chunked_body.rb +31 -0
- data/lib/zipline/tempfile_body.rb +52 -0
- data/lib/zipline/version.rb +1 -1
- data/lib/zipline/zip_generator.rb +31 -29
- data/lib/zipline.rb +36 -5
- data/spec/lib/zipline/zip_generator_spec.rb +0 -82
- data/spec/lib/zipline/zipline_spec.rb +68 -0
- data/spec/spec_helper.rb +8 -7
- data/zipline.gemspec +9 -2
- metadata +98 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca44760a8a5c6019544aa77857692b43d4cd9f429395173a54b779f276f214f2
|
4
|
+
data.tar.gz: c9aec0dc791f84a315658ae9405e88f1d5b7348822befa69e61c92e261ff3a69
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c46de9ba175df42d54c36a37dceddb77cf7816e058528750fe0b05c54313aba1992b8ba12d40b9f029a33c088c79a214d3e50e56cbd0b295c74062fe49c7781
|
7
|
+
data.tar.gz: 5022768afbe367ca08c586b33d16f8a044ad79c7cde80b79be4a3d1c9b18c16d2b0d9cdb9d82f75e3df338d101eda5dce80a099c1261e2e3d828ac637569d790
|
data/.github/workflows/ci.yml
CHANGED
data/Gemfile
CHANGED
@@ -2,13 +2,3 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
# Specify your gem's dependencies in zipline.gemspec
|
4
4
|
gemspec
|
5
|
-
|
6
|
-
group :development, :test do
|
7
|
-
gem 'rspec', '~> 3'
|
8
|
-
gem 'fog-aws'
|
9
|
-
gem 'activesupport'
|
10
|
-
gem 'aws-sdk-s3'
|
11
|
-
gem 'carrierwave'
|
12
|
-
gem 'paperclip'
|
13
|
-
gem 'rake'
|
14
|
-
end
|
data/README.md
CHANGED
@@ -41,7 +41,10 @@ class MyController < ApplicationController
|
|
41
41
|
# responds to :url, :path or :file.
|
42
42
|
# :modification_time is an optional third argument you can use.
|
43
43
|
files = users.map{ |user| [user.avatar, "#{user.username}.png", modification_time: 1.day.ago] }
|
44
|
-
|
44
|
+
|
45
|
+
# we can force duplicate file names to be renamed, or raise an error
|
46
|
+
# we can also pass in our own writer if required to conform with the Delegated [ZipTricks::Streamer object](https://github.com/WeTransfer/zip_tricks/blob/main/lib/zip_tricks/streamer.rb#L147) object.
|
47
|
+
zipline(files, 'avatars.zip', auto_rename_duplicate_filenames: true)
|
45
48
|
end
|
46
49
|
end
|
47
50
|
```
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Zipline
|
2
|
+
# A body wrapper that emits chunked responses, creating valid
|
3
|
+
# "Transfer-Encoding: chunked" HTTP response body. This is copied from Rack::Chunked::Body,
|
4
|
+
# because Rack is not going to include that class after version 3.x
|
5
|
+
# Rails has a substitute class for this inside ActionController::Streaming,
|
6
|
+
# but that module is a private constant in the Rails codebase, and is thus
|
7
|
+
# considered "private" from the Rails standpoint. It is not that much code to
|
8
|
+
# carry, so we copy it into our code.
|
9
|
+
class Chunked
|
10
|
+
TERM = "\r\n"
|
11
|
+
TAIL = "0#{TERM}"
|
12
|
+
|
13
|
+
def initialize(body)
|
14
|
+
@body = body
|
15
|
+
end
|
16
|
+
|
17
|
+
# For each string yielded by the response body, yield
|
18
|
+
# the element in chunked encoding - and finish off with a terminator
|
19
|
+
def each
|
20
|
+
term = TERM
|
21
|
+
@body.each do |chunk|
|
22
|
+
size = chunk.bytesize
|
23
|
+
next if size == 0
|
24
|
+
|
25
|
+
yield [size.to_s(16), term, chunk.b, term].join
|
26
|
+
end
|
27
|
+
yield TAIL
|
28
|
+
yield term
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Zipline
|
2
|
+
# Contains a file handle which can be closed once the response finishes sending.
|
3
|
+
# It supports `to_path` so that `Rack::Sendfile` can intercept it
|
4
|
+
class TempfileBody
|
5
|
+
TEMPFILE_NAME_PREFIX = "zipline-tf-body-"
|
6
|
+
attr_reader :tempfile
|
7
|
+
|
8
|
+
# @param body[#each] the enumerable that yields bytes, usually a `RackBody`.
|
9
|
+
# The `body` will be read in full immediately and closed.
|
10
|
+
def initialize(env, body)
|
11
|
+
@tempfile = Tempfile.new(TEMPFILE_NAME_PREFIX)
|
12
|
+
# Rack::TempfileReaper calls close! on tempfiles which get buffered
|
13
|
+
# We wil assume that it works fine with Rack::Sendfile (i.e. the path
|
14
|
+
# to the file getting served gets used before we unlink the tempfile)
|
15
|
+
env['rack.tempfiles'] ||= []
|
16
|
+
env['rack.tempfiles'] << @tempfile
|
17
|
+
|
18
|
+
@tempfile.binmode
|
19
|
+
|
20
|
+
body.each { |bytes| @tempfile << bytes }
|
21
|
+
body.close if body.respond_to?(:close)
|
22
|
+
|
23
|
+
@tempfile.flush
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns the size of the contained `Tempfile` so that a correct
|
27
|
+
# Content-Length header can be set
|
28
|
+
#
|
29
|
+
# @return [Integer]
|
30
|
+
def size
|
31
|
+
@tempfile.size
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns the path to the `Tempfile`, so that Rack::Sendfile can send this response
|
35
|
+
# using the downstream webserver
|
36
|
+
#
|
37
|
+
# @return [String]
|
38
|
+
def to_path
|
39
|
+
@tempfile.to_path
|
40
|
+
end
|
41
|
+
|
42
|
+
# Stream the file's contents if `Rack::Sendfile` isn't present.
|
43
|
+
#
|
44
|
+
# @return [void]
|
45
|
+
def each
|
46
|
+
@tempfile.rewind
|
47
|
+
while chunk = @tempfile.read(16384)
|
48
|
+
yield chunk
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/zipline/version.rb
CHANGED
@@ -3,43 +3,35 @@
|
|
3
3
|
module Zipline
|
4
4
|
class ZipGenerator
|
5
5
|
# takes an array of pairs [[uploader, filename], ... ]
|
6
|
-
def initialize(files)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
#this is supposed to be streamed!
|
11
|
-
def to_s
|
12
|
-
throw "stop!"
|
13
|
-
end
|
14
|
-
|
15
|
-
def each(&block)
|
16
|
-
fake_io_writer = ZipTricks::BlockWrite.new(&block)
|
17
|
-
# ZipTricks outputs lots of strings in rapid succession, and with
|
18
|
-
# servers it can be beneficial to avoid doing too many tiny writes so that
|
19
|
-
# the number of syscalls is minimized. See https://github.com/WeTransfer/zip_tricks/issues/78
|
20
|
-
# There is a built-in facility for this in ZipTricks which can be used to implement
|
21
|
-
# some cheap buffering here (it exists both in version 4 and version 5). The buffer is really
|
22
|
-
# tiny and roughly equal to the medium Linux socket buffer size (16 KB). Although output
|
23
|
-
# will be not so immediate with this buffering the overall performance will be better,
|
24
|
-
# especially with multiple clients being serviced at the same time.
|
25
|
-
# Note that the WriteBuffer writes the same, retained String object - but the contents
|
26
|
-
# of that object changes between calls. This should work fine with servers where the
|
27
|
-
# contents of the string gets written to a socket immediately before the execution inside
|
28
|
-
# the WriteBuffer resumes), but if the strings get retained somewhere - like in an Array -
|
29
|
-
# this might pose a problem. Unlikely that it will be an issue here though.
|
30
|
-
write_buffer_size = 16 * 1024
|
31
|
-
write_buffer = ZipTricks::WriteBuffer.new(fake_io_writer, write_buffer_size)
|
32
|
-
ZipTricks::Streamer.open(write_buffer) do |streamer|
|
33
|
-
@files.each do |file, name, options = {}|
|
6
|
+
def initialize(files, **kwargs_for_streamer)
|
7
|
+
# Use RackBody as it has buffering built-in in zip_tricks 5.x+
|
8
|
+
@body = ZipTricks::RackBody.new(**kwargs_for_streamer) do |streamer|
|
9
|
+
files.each do |file, name, options = {}|
|
34
10
|
handle_file(streamer, file, name.to_s, options)
|
35
11
|
end
|
36
12
|
end
|
37
|
-
|
13
|
+
end
|
14
|
+
|
15
|
+
def each(&block)
|
16
|
+
return to_enum(:each) unless block_given?
|
17
|
+
@body.each(&block)
|
18
|
+
rescue => e
|
19
|
+
# Since most APM packages do not trace errors occurring within streaming
|
20
|
+
# Rack bodies, it can be helpful to print the error to the Rails log at least
|
21
|
+
error_message = "zipline: an exception (#{e.inspect}) was raised when serving the ZIP body."
|
22
|
+
error_message += " The error occurred when handling #{@filename.inspect}" if @filename
|
23
|
+
logger.error(error_message)
|
24
|
+
raise
|
38
25
|
end
|
39
26
|
|
40
27
|
def handle_file(streamer, file, name, options)
|
41
28
|
file = normalize(file)
|
29
|
+
|
30
|
+
# Store the filename so that a sensible error message can be displayed in the log
|
31
|
+
# if writing this particular file fails
|
32
|
+
@filename = name
|
42
33
|
write_file(streamer, file, name, options)
|
34
|
+
@filename = nil
|
43
35
|
end
|
44
36
|
|
45
37
|
# This extracts either a url or a local file from the provided file.
|
@@ -106,6 +98,16 @@ module Zipline
|
|
106
98
|
|
107
99
|
private
|
108
100
|
|
101
|
+
def logger
|
102
|
+
# Rails is not defined in our tests, and might as well not be defined
|
103
|
+
# elsewhere - or the logger might not be configured correctly
|
104
|
+
if defined?(Rails.logger) && Rails.logger
|
105
|
+
Rails.logger
|
106
|
+
else
|
107
|
+
Logger.new($stderr)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
109
111
|
def is_active_storage_attachment?(file)
|
110
112
|
defined?(ActiveStorage::Attachment) && file.is_a?(ActiveStorage::Attachment)
|
111
113
|
end
|
data/lib/zipline.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'content_disposition'
|
2
|
-
require
|
2
|
+
require 'zipline/version'
|
3
3
|
require 'zip_tricks'
|
4
|
-
require
|
4
|
+
require 'zipline/zip_generator'
|
5
|
+
require 'zipline/chunked_body'
|
6
|
+
require 'zipline/tempfile_body'
|
5
7
|
|
6
8
|
# class MyController < ApplicationController
|
7
9
|
# include Zipline
|
@@ -12,13 +14,42 @@ require "zipline/zip_generator"
|
|
12
14
|
# end
|
13
15
|
# end
|
14
16
|
module Zipline
|
15
|
-
def zipline(files, zipname = 'zipline.zip')
|
16
|
-
zip_generator = ZipGenerator.new(files)
|
17
|
+
def zipline(files, zipname = 'zipline.zip', **kwargs_for_new)
|
18
|
+
zip_generator = ZipGenerator.new(files, **kwargs_for_new)
|
17
19
|
headers['Content-Disposition'] = ContentDisposition.format(disposition: 'attachment', filename: zipname)
|
18
20
|
headers['Content-Type'] = Mime::Type.lookup_by_extension('zip').to_s
|
19
21
|
response.sending_file = true
|
20
22
|
response.cache_control[:public] ||= false
|
21
|
-
|
23
|
+
|
24
|
+
# Disables Rack::ETag if it is enabled (prevent buffering)
|
25
|
+
# see https://github.com/rack/rack/issues/1619#issuecomment-606315714
|
22
26
|
self.response.headers['Last-Modified'] = Time.now.httpdate
|
27
|
+
|
28
|
+
if request.get_header("HTTP_VERSION") == "HTTP/1.0"
|
29
|
+
# If HTTP/1.0 is used it is not possible to stream, and if that happens it usually will be
|
30
|
+
# unclear why buffering is happening. Some info in the log is the least one can do.
|
31
|
+
logger.warn { "The downstream HTTP proxy/LB insists on HTTP/1.0 protocol, ZIP response will be buffered." } if logger
|
32
|
+
|
33
|
+
# If we use Rack::ContentLength it would run through our ZIP block twice - once to calculate the content length
|
34
|
+
# of the response, and once - to serve. We can trade performance for disk space and buffer the response into a Tempfile
|
35
|
+
# since we are already buffering.
|
36
|
+
tempfile_body = TempfileBody.new(request.env, zip_generator)
|
37
|
+
headers["Content-Length"] = tempfile_body.size.to_s
|
38
|
+
headers["X-Zipline-Output"] = "buffered"
|
39
|
+
self.response_body = tempfile_body
|
40
|
+
else
|
41
|
+
# Disable buffering for both nginx and Google Load Balancer, see
|
42
|
+
# https://cloud.google.com/appengine/docs/flexible/how-requests-are-handled?tab=python#x-accel-buffering
|
43
|
+
response.headers["X-Accel-Buffering"] = "no"
|
44
|
+
|
45
|
+
# Make sure Rack::ContentLength does not try to compute a content length,
|
46
|
+
# and remove the one already set
|
47
|
+
headers.delete("Content-Length")
|
48
|
+
|
49
|
+
# and send out in chunked encoding
|
50
|
+
headers["Transfer-Encoding"] = "chunked"
|
51
|
+
headers["X-Zipline-Output"] = "streamed"
|
52
|
+
self.response_body = Chunked.new(zip_generator)
|
53
|
+
end
|
23
54
|
end
|
24
55
|
end
|
@@ -185,86 +185,4 @@ describe Zipline::ZipGenerator do
|
|
185
185
|
end
|
186
186
|
end
|
187
187
|
end
|
188
|
-
|
189
|
-
describe '.write_file' do
|
190
|
-
let(:file) { StringIO.new('passthrough') }
|
191
|
-
|
192
|
-
context 'when passing an ActiveStorage::Filename object as filename' do
|
193
|
-
let(:filename) { ActiveStorage::Filename.new('test') }
|
194
|
-
|
195
|
-
let(:generator) do
|
196
|
-
Zipline::ZipGenerator.new([[file, filename]])
|
197
|
-
end
|
198
|
-
|
199
|
-
it 'passes a string as filename to ZipTricks' do
|
200
|
-
allow(file).to receive(:url).and_return('fakeurl')
|
201
|
-
expect_any_instance_of(ZipTricks::Streamer).to receive(:write_deflated_file)
|
202
|
-
.with('test')
|
203
|
-
generator.each { |_| 'Test' }
|
204
|
-
end
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
describe 'passing an options hash' do
|
209
|
-
let(:file) { StringIO.new('passthrough') }
|
210
|
-
|
211
|
-
context 'with optional arguments' do
|
212
|
-
let(:mtime) { 1.day.ago }
|
213
|
-
let(:generator) do
|
214
|
-
Zipline::ZipGenerator.new([[file, 'test', modification_time: mtime]])
|
215
|
-
end
|
216
|
-
|
217
|
-
it 'passes the options hash through handle_file' do
|
218
|
-
expect(generator).to receive(:handle_file)
|
219
|
-
.with(anything, anything, anything, modification_time: mtime)
|
220
|
-
generator.each { |_| 'Test' }
|
221
|
-
end
|
222
|
-
|
223
|
-
it 'passes the options hash to ZipTricks as kwargs' do
|
224
|
-
allow(file).to receive(:url).and_return('fakeurl')
|
225
|
-
expect_any_instance_of(ZipTricks::Streamer).to receive(:write_deflated_file)
|
226
|
-
.with(anything, modification_time: mtime)
|
227
|
-
generator.each { |_| 'Test' }
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
context 'without optional arguments' do
|
232
|
-
let(:generator) do
|
233
|
-
Zipline::ZipGenerator.new([[file, 'test']])
|
234
|
-
end
|
235
|
-
|
236
|
-
it 'passes the options hash through handle_file' do
|
237
|
-
expect(generator).to receive(:handle_file)
|
238
|
-
.with(anything, anything, anything, {})
|
239
|
-
generator.each { |_| 'Test' }
|
240
|
-
end
|
241
|
-
|
242
|
-
it 'passes the options hash to ZipTricks as kwargs' do
|
243
|
-
allow(file).to receive(:url).and_return('fakeurl')
|
244
|
-
expect_any_instance_of(ZipTricks::Streamer).to receive(:write_deflated_file)
|
245
|
-
.with(anything)
|
246
|
-
generator.each { |_| 'Test' }
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
context 'with extra invalid options' do
|
251
|
-
let(:mtime) { 1.day.ago }
|
252
|
-
let(:generator) do
|
253
|
-
Zipline::ZipGenerator.new([[file, 'test', modification_time: mtime, extra: 'invalid']])
|
254
|
-
end
|
255
|
-
|
256
|
-
it 'passes the whole options hash through handle_file' do
|
257
|
-
expect(generator).to receive(:handle_file)
|
258
|
-
.with(anything, anything, anything, { modification_time: mtime, extra: 'invalid' })
|
259
|
-
generator.each { |_| 'Test' }
|
260
|
-
end
|
261
|
-
|
262
|
-
it 'only passes the kwargs to ZipTricks that it expects (i.e., :modification_time)' do
|
263
|
-
allow(file).to receive(:url).and_return('fakeurl')
|
264
|
-
expect_any_instance_of(ZipTricks::Streamer).to receive(:write_deflated_file)
|
265
|
-
.with(anything, modification_time: mtime)
|
266
|
-
generator.each { |_| 'Test' }
|
267
|
-
end
|
268
|
-
end
|
269
|
-
end
|
270
188
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'action_controller'
|
3
|
+
|
4
|
+
describe Zipline do
|
5
|
+
before { Fog.mock! }
|
6
|
+
|
7
|
+
class FakeController < ActionController::Base
|
8
|
+
include Zipline
|
9
|
+
def download_zip
|
10
|
+
files = [
|
11
|
+
[StringIO.new("File content goes here"), "one.txt"],
|
12
|
+
[StringIO.new("Some other content goes here"), "two.txt"]
|
13
|
+
]
|
14
|
+
zipline(files, 'myfiles.zip', auto_rename_duplicate_filenames: false)
|
15
|
+
end
|
16
|
+
|
17
|
+
class FailingIO < StringIO
|
18
|
+
def read(*)
|
19
|
+
raise "Something wonky"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def download_zip_with_error_during_streaming
|
24
|
+
files = [
|
25
|
+
[StringIO.new("File content goes here"), "one.txt"],
|
26
|
+
[FailingIO.new("This will fail half-way"), "two.txt"]
|
27
|
+
]
|
28
|
+
zipline(files, 'myfiles.zip', auto_rename_duplicate_filenames: false)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'passes keyword parameters to ZipTricks::Streamer' do
|
33
|
+
fake_rack_env = {
|
34
|
+
"HTTP_VERSION" => "HTTP/1.0",
|
35
|
+
"REQUEST_METHOD" => "GET",
|
36
|
+
"SCRIPT_NAME" => "",
|
37
|
+
"PATH_INFO" => "/download",
|
38
|
+
"QUERY_STRING" => "",
|
39
|
+
"SERVER_NAME" => "host.example",
|
40
|
+
"rack.input" => StringIO.new,
|
41
|
+
}
|
42
|
+
expect(ZipTricks::Streamer).to receive(:new).with(anything, auto_rename_duplicate_filenames: false).and_call_original
|
43
|
+
|
44
|
+
status, headers, body = FakeController.action(:download_zip).call(fake_rack_env)
|
45
|
+
|
46
|
+
expect(headers['Content-Disposition']).to eq("attachment; filename=\"myfiles.zip\"; filename*=UTF-8''myfiles.zip")
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'sends the exception raised in the streaming body to the Rails logger' do
|
50
|
+
fake_rack_env = {
|
51
|
+
"HTTP_VERSION" => "HTTP/1.0",
|
52
|
+
"REQUEST_METHOD" => "GET",
|
53
|
+
"SCRIPT_NAME" => "",
|
54
|
+
"PATH_INFO" => "/download",
|
55
|
+
"QUERY_STRING" => "",
|
56
|
+
"SERVER_NAME" => "host.example",
|
57
|
+
"rack.input" => StringIO.new,
|
58
|
+
}
|
59
|
+
expect(ZipTricks::Streamer).to receive(:new).with(anything, auto_rename_duplicate_filenames: false).and_call_original
|
60
|
+
fake_logger = double()
|
61
|
+
expect(Logger).to receive(:new).and_return(fake_logger)
|
62
|
+
expect(fake_logger).to receive(:error).with(instance_of(String))
|
63
|
+
|
64
|
+
expect {
|
65
|
+
FakeController.action(:download_zip_with_error_during_streaming).call(fake_rack_env)
|
66
|
+
}.to raise_error(/Something wonky/)
|
67
|
+
end
|
68
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,22 +1,23 @@
|
|
1
1
|
require 'rspec'
|
2
2
|
require 'active_support'
|
3
3
|
require 'active_support/core_ext'
|
4
|
+
require 'action_dispatch'
|
5
|
+
|
4
6
|
require 'zipline'
|
5
7
|
require 'paperclip'
|
6
8
|
require 'fog-aws'
|
7
9
|
require 'carrierwave'
|
8
10
|
|
9
|
-
Dir["#{File.expand_path('..', __FILE__)}/support/**/*.rb"].each { |f| require f }
|
11
|
+
Dir["#{File.expand_path('..', __FILE__)}/support/**/*.rb"].sort.each { |f| require f }
|
10
12
|
|
11
13
|
CarrierWave.configure do |config|
|
12
14
|
config.fog_provider = 'fog/aws'
|
13
15
|
config.fog_credentials = {
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
provider: 'AWS',
|
17
|
+
aws_access_key_id: 'dummy',
|
18
|
+
aws_secret_access_key: 'data',
|
19
|
+
region: 'us-west-2',
|
20
|
+
}
|
20
21
|
end
|
21
22
|
|
22
23
|
RSpec.configure do |config|
|
data/zipline.gemspec
CHANGED
@@ -20,8 +20,15 @@ Gem::Specification.new do |gem|
|
|
20
20
|
|
21
21
|
gem.add_dependency 'actionpack', ['>= 6.0', '< 8.0']
|
22
22
|
gem.add_dependency 'content_disposition', '~> 1.0'
|
23
|
-
gem.add_dependency 'zip_tricks', ['
|
23
|
+
gem.add_dependency 'zip_tricks', ['~> 4.8', '< 6'] # Minimum to 4.8.3 which is the last-released MIT version
|
24
|
+
|
25
|
+
gem.add_development_dependency 'rspec', '~> 3'
|
26
|
+
gem.add_development_dependency 'fog-aws'
|
27
|
+
gem.add_development_dependency 'aws-sdk-s3'
|
28
|
+
gem.add_development_dependency 'carrierwave'
|
29
|
+
gem.add_development_dependency 'paperclip'
|
30
|
+
gem.add_development_dependency 'rake'
|
24
31
|
|
25
32
|
# https://github.com/rspec/rspec-mocks/issues/1457
|
26
|
-
gem.add_development_dependency 'rspec-mocks',
|
33
|
+
gem.add_development_dependency 'rspec-mocks', '~> 3.12'
|
27
34
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zipline
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ram Dobson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-02-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|
@@ -48,42 +48,120 @@ dependencies:
|
|
48
48
|
name: zip_tricks
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
|
-
- - "
|
51
|
+
- - "~>"
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: 4.
|
53
|
+
version: '4.8'
|
54
54
|
- - "<"
|
55
55
|
- !ruby/object:Gem::Version
|
56
|
-
version: '6
|
56
|
+
version: '6'
|
57
57
|
type: :runtime
|
58
58
|
prerelease: false
|
59
59
|
version_requirements: !ruby/object:Gem::Requirement
|
60
60
|
requirements:
|
61
|
-
- - "
|
61
|
+
- - "~>"
|
62
62
|
- !ruby/object:Gem::Version
|
63
|
-
version: 4.
|
63
|
+
version: '4.8'
|
64
64
|
- - "<"
|
65
65
|
- !ruby/object:Gem::Version
|
66
|
-
version: '6
|
66
|
+
version: '6'
|
67
67
|
- !ruby/object:Gem::Dependency
|
68
|
-
name: rspec
|
68
|
+
name: rspec
|
69
69
|
requirement: !ruby/object:Gem::Requirement
|
70
70
|
requirements:
|
71
71
|
- - "~>"
|
72
72
|
- !ruby/object:Gem::Version
|
73
|
-
version: '3
|
74
|
-
|
73
|
+
version: '3'
|
74
|
+
type: :development
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - "~>"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '3'
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: fog-aws
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: aws-sdk-s3
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
- !ruby/object:Gem::Dependency
|
110
|
+
name: carrierwave
|
111
|
+
requirement: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
type: :development
|
117
|
+
prerelease: false
|
118
|
+
version_requirements: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
- !ruby/object:Gem::Dependency
|
124
|
+
name: paperclip
|
125
|
+
requirement: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - ">="
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0'
|
130
|
+
type: :development
|
131
|
+
prerelease: false
|
132
|
+
version_requirements: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - ">="
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '0'
|
137
|
+
- !ruby/object:Gem::Dependency
|
138
|
+
name: rake
|
139
|
+
requirement: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - ">="
|
75
142
|
- !ruby/object:Gem::Version
|
76
|
-
version:
|
143
|
+
version: '0'
|
77
144
|
type: :development
|
78
145
|
prerelease: false
|
79
146
|
version_requirements: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
- !ruby/object:Gem::Dependency
|
152
|
+
name: rspec-mocks
|
153
|
+
requirement: !ruby/object:Gem::Requirement
|
80
154
|
requirements:
|
81
155
|
- - "~>"
|
82
156
|
- !ruby/object:Gem::Version
|
83
|
-
version: '3.
|
84
|
-
|
157
|
+
version: '3.12'
|
158
|
+
type: :development
|
159
|
+
prerelease: false
|
160
|
+
version_requirements: !ruby/object:Gem::Requirement
|
161
|
+
requirements:
|
162
|
+
- - "~>"
|
85
163
|
- !ruby/object:Gem::Version
|
86
|
-
version: 3.
|
164
|
+
version: '3.12'
|
87
165
|
description: a module for streaming dynamically generated zip files
|
88
166
|
email:
|
89
167
|
- ram.dobson@solsystemscompany.com
|
@@ -97,10 +175,13 @@ files:
|
|
97
175
|
- README.md
|
98
176
|
- Rakefile
|
99
177
|
- lib/zipline.rb
|
178
|
+
- lib/zipline/chunked_body.rb
|
179
|
+
- lib/zipline/tempfile_body.rb
|
100
180
|
- lib/zipline/version.rb
|
101
181
|
- lib/zipline/zip_generator.rb
|
102
182
|
- spec/fakefile.txt
|
103
183
|
- spec/lib/zipline/zip_generator_spec.rb
|
184
|
+
- spec/lib/zipline/zipline_spec.rb
|
104
185
|
- spec/spec_helper.rb
|
105
186
|
- zipline.gemspec
|
106
187
|
homepage: http://github.com/fringd/zipline
|
@@ -122,11 +203,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
203
|
- !ruby/object:Gem::Version
|
123
204
|
version: '0'
|
124
205
|
requirements: []
|
125
|
-
rubygems_version: 3.
|
206
|
+
rubygems_version: 3.3.26
|
126
207
|
signing_key:
|
127
208
|
specification_version: 4
|
128
209
|
summary: stream zip files from rails
|
129
210
|
test_files:
|
130
211
|
- spec/fakefile.txt
|
131
212
|
- spec/lib/zipline/zip_generator_spec.rb
|
213
|
+
- spec/lib/zipline/zipline_spec.rb
|
132
214
|
- spec/spec_helper.rb
|