zipline 0.0.10 → 0.0.11
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 +7 -0
- data/Gemfile +2 -1
- data/README.md +24 -7
- data/lib/zipline.rb +1 -5
- data/lib/zipline/version.rb +1 -1
- data/lib/zipline/zip_generator.rb +24 -38
- data/spec/spec_helper.rb +1 -1
- data/zipline.gemspec +4 -4
- metadata +33 -38
- data/lib/zipline/fake_stream.rb +0 -43
- data/lib/zipline/output_stream.rb +0 -55
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f2f04b0aaf25dba39d30fa57d3b7dee52ab4f7db
|
4
|
+
data.tar.gz: af226cf8bd006c78e95e7fba5918b8888ab15893
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: af1e5037946364838761db1c030dcb7c5480f779dc97a88117bcfc3f923097f598d1571ec87a27f83b1dc08c72e43b1176b5e379e5eca25f8f8cf9f30abd1eca
|
7
|
+
data.tar.gz: eb28c47cae2d33c2176242667d240747c632c71c210650645e35420d6af7ea5939319a14cefbc9b7e163c613b8e0acfebf524690c71f8ef6b795dbc4431f6d17
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -17,10 +17,13 @@ And then execute:
|
|
17
17
|
|
18
18
|
## Usage
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
Set up some models with [carrierwave](https://github.com/jnicklas/carrierwave)
|
21
|
+
or [paperclip](https://github.com/thoughtbot/paperclip). Right now only plain
|
22
|
+
file storage and S3 are supported in the case of
|
23
|
+
[carrierwave](https://github.com/jnicklas/carrierwave) and only plain file
|
24
|
+
storage and S3 are supported in the case of
|
25
|
+
[paperclip](https://github.com/thoughtbot/paperclip).
|
26
|
+
You'll need to be using puma or some other server that supports streaming output.
|
24
27
|
|
25
28
|
class MyController < ApplicationController
|
26
29
|
# enable streaming responses
|
@@ -29,13 +32,29 @@ You'll need to be using [unicorn](http://unicorn.bogomips.org/) or rainbows or s
|
|
29
32
|
include Zipline
|
30
33
|
|
31
34
|
def index
|
32
|
-
users= User.all
|
35
|
+
users = User.all
|
36
|
+
# you can replace user.avatar with any stream or any object that
|
37
|
+
# responds to :url
|
33
38
|
files = users.map{ |user| [user.avatar, "#{user.username}.png"] }
|
34
39
|
zipline( files, 'avatars.zip')
|
35
40
|
end
|
36
41
|
end
|
37
42
|
|
38
43
|
For directories, just give the files names like "directory/file".
|
44
|
+
|
45
|
+
To stream files from a remote URL, use open-uri with a [lazy enumerator](http://ruby-doc.org/core-2.0.0/Enumerator/Lazy.html):
|
46
|
+
|
47
|
+
require 'open-uri'
|
48
|
+
avatars = [
|
49
|
+
# remote_url zip_path
|
50
|
+
[ 'http://www.example.com/user1.png', 'avatars/user1.png' ]
|
51
|
+
[ 'http://www.example.com/user2.png', 'avatars/user2.png' ]
|
52
|
+
[ 'http://www.example.com/user3.png', 'avatars/user3.png' ]
|
53
|
+
]
|
54
|
+
file_mappings = avatars
|
55
|
+
.lazy # Lazy allows us to begin sending the download immediately instead of waiting to download everything
|
56
|
+
.map { |url, path| [open(url), path] }
|
57
|
+
zipline(file_mappings, 'avatars.zip')
|
39
58
|
|
40
59
|
## Contributing
|
41
60
|
|
@@ -48,5 +67,3 @@ For directories, just give the files names like "directory/file".
|
|
48
67
|
## TODO (possible contributions?)
|
49
68
|
|
50
69
|
* tests!
|
51
|
-
* extract library for plain ruby streaming zips, which this will depend on.
|
52
|
-
* get my changes to support streaming zips checked in to the rubyzip library.
|
data/lib/zipline.rb
CHANGED
data/lib/zipline/version.rb
CHANGED
@@ -13,21 +13,21 @@ module Zipline
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def each(&block)
|
16
|
-
|
17
|
-
|
18
|
-
@files.each {|file, name| handle_file(
|
16
|
+
fake_io_writer = ZipTricks::BlockWrite.new(&block)
|
17
|
+
ZipTricks::Streamer.open(fake_io_writer) do |streamer|
|
18
|
+
@files.each {|file, name| handle_file(streamer, file, name) }
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
def handle_file(
|
22
|
+
def handle_file(streamer, file, name)
|
23
23
|
file = normalize(file)
|
24
24
|
name = uniquify_name(name)
|
25
|
-
write_file(
|
25
|
+
write_file(streamer, file, name)
|
26
26
|
end
|
27
27
|
|
28
28
|
def normalize(file)
|
29
29
|
unless is_io?(file)
|
30
|
-
if file.respond_to?(:url)
|
30
|
+
if file.respond_to?(:url) || file.respond_to?(:expiring_url)
|
31
31
|
file = file
|
32
32
|
elsif file.respond_to? :file
|
33
33
|
file = File.open(file.file)
|
@@ -40,42 +40,28 @@ module Zipline
|
|
40
40
|
file
|
41
41
|
end
|
42
42
|
|
43
|
-
def
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
zip << data
|
60
|
-
data.bytesize
|
61
|
-
end
|
43
|
+
def write_file(streamer, file, name)
|
44
|
+
streamer.write_stored_file(name) do |writer_for_file|
|
45
|
+
if file.respond_to?(:url) || file.respond_to?(:expiring_url)
|
46
|
+
# expiring_url seems needed for paperclip to work
|
47
|
+
the_remote_url = file.respond_to?(:expiring_url) ? file.expiring_url : file.url
|
48
|
+
c = Curl::Easy.new(the_remote_url) do |curl|
|
49
|
+
curl.on_body do |data|
|
50
|
+
writer_for_file << data
|
51
|
+
data.bytesize
|
52
|
+
end
|
53
|
+
end
|
54
|
+
c.perform
|
55
|
+
elsif is_io?(file)
|
56
|
+
IO.copy_stream(file, writer_for_file)
|
57
|
+
else
|
58
|
+
raise(ArgumentError, 'Bad File/Stream')
|
62
59
|
end
|
63
|
-
c.perform
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def get_size(file)
|
68
|
-
if is_io?(file) || file.respond_to?(:size)
|
69
|
-
file.size
|
70
|
-
elsif file.respond_to? :content_length
|
71
|
-
file.content_length
|
72
|
-
else
|
73
|
-
throw 'cannot determine file size'
|
74
60
|
end
|
75
61
|
end
|
76
62
|
|
77
|
-
def is_io?(
|
78
|
-
|
63
|
+
def is_io?(io_ish)
|
64
|
+
io_ish.respond_to? :read
|
79
65
|
end
|
80
66
|
|
81
67
|
def uniquify_name(name)
|
data/spec/spec_helper.rb
CHANGED
data/zipline.gemspec
CHANGED
@@ -4,7 +4,7 @@ require File.expand_path('../lib/zipline/version', __FILE__)
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ["Ram Dobson"]
|
6
6
|
gem.email = ["ram.dobson@solsystemscompany.com"]
|
7
|
-
gem.description = %q{
|
7
|
+
gem.description = %q{a module for streaming dynamically generated zip files}
|
8
8
|
gem.summary = %q{stream zip files from rails}
|
9
9
|
gem.homepage = "http://github.com/fringd/zipline"
|
10
10
|
|
@@ -15,7 +15,7 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = Zipline::VERSION
|
17
17
|
|
18
|
-
gem.add_dependency '
|
19
|
-
gem.add_dependency 'rails', ['>= 3.2.1', '<
|
20
|
-
gem.add_dependency 'curb'
|
18
|
+
gem.add_dependency 'zip_tricks', ['>= 4.0.0', '<= 5.0.0']
|
19
|
+
gem.add_dependency 'rails', ['>= 3.2.1', '< 5.1']
|
20
|
+
gem.add_dependency 'curb', ['>= 0.8.0', '< 0.10']
|
21
21
|
end
|
metadata
CHANGED
@@ -1,78 +1,76 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zipline
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.11
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Ram Dobson
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2016-09-06 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
14
|
+
name: zip_tricks
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
22
|
-
- - <=
|
19
|
+
version: 4.0.0
|
20
|
+
- - "<="
|
23
21
|
- !ruby/object:Gem::Version
|
24
|
-
version:
|
22
|
+
version: 5.0.0
|
25
23
|
type: :runtime
|
26
24
|
prerelease: false
|
27
25
|
version_requirements: !ruby/object:Gem::Requirement
|
28
|
-
none: false
|
29
26
|
requirements:
|
30
|
-
- -
|
27
|
+
- - ">="
|
31
28
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
33
|
-
- - <=
|
29
|
+
version: 4.0.0
|
30
|
+
- - "<="
|
34
31
|
- !ruby/object:Gem::Version
|
35
|
-
version:
|
32
|
+
version: 5.0.0
|
36
33
|
- !ruby/object:Gem::Dependency
|
37
34
|
name: rails
|
38
35
|
requirement: !ruby/object:Gem::Requirement
|
39
|
-
none: false
|
40
36
|
requirements:
|
41
|
-
- -
|
37
|
+
- - ">="
|
42
38
|
- !ruby/object:Gem::Version
|
43
39
|
version: 3.2.1
|
44
|
-
- - <
|
40
|
+
- - "<"
|
45
41
|
- !ruby/object:Gem::Version
|
46
|
-
version: '
|
42
|
+
version: '5.1'
|
47
43
|
type: :runtime
|
48
44
|
prerelease: false
|
49
45
|
version_requirements: !ruby/object:Gem::Requirement
|
50
|
-
none: false
|
51
46
|
requirements:
|
52
|
-
- -
|
47
|
+
- - ">="
|
53
48
|
- !ruby/object:Gem::Version
|
54
49
|
version: 3.2.1
|
55
|
-
- - <
|
50
|
+
- - "<"
|
56
51
|
- !ruby/object:Gem::Version
|
57
|
-
version: '
|
52
|
+
version: '5.1'
|
58
53
|
- !ruby/object:Gem::Dependency
|
59
54
|
name: curb
|
60
55
|
requirement: !ruby/object:Gem::Requirement
|
61
|
-
none: false
|
62
56
|
requirements:
|
63
|
-
- -
|
57
|
+
- - ">="
|
64
58
|
- !ruby/object:Gem::Version
|
65
|
-
version:
|
59
|
+
version: 0.8.0
|
60
|
+
- - "<"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0.10'
|
66
63
|
type: :runtime
|
67
64
|
prerelease: false
|
68
65
|
version_requirements: !ruby/object:Gem::Requirement
|
69
|
-
none: false
|
70
66
|
requirements:
|
71
|
-
- -
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 0.8.0
|
70
|
+
- - "<"
|
72
71
|
- !ruby/object:Gem::Version
|
73
|
-
version: '0'
|
74
|
-
description:
|
75
|
-
zip files
|
72
|
+
version: '0.10'
|
73
|
+
description: a module for streaming dynamically generated zip files
|
76
74
|
email:
|
77
75
|
- ram.dobson@solsystemscompany.com
|
78
76
|
executables: []
|
@@ -84,8 +82,6 @@ files:
|
|
84
82
|
- README.md
|
85
83
|
- Rakefile
|
86
84
|
- lib/zipline.rb
|
87
|
-
- lib/zipline/fake_stream.rb
|
88
|
-
- lib/zipline/output_stream.rb
|
89
85
|
- lib/zipline/version.rb
|
90
86
|
- lib/zipline/zip_generator.rb
|
91
87
|
- spec/lib/zipline/zip_generator_spec.rb
|
@@ -93,27 +89,26 @@ files:
|
|
93
89
|
- zipline.gemspec
|
94
90
|
homepage: http://github.com/fringd/zipline
|
95
91
|
licenses: []
|
92
|
+
metadata: {}
|
96
93
|
post_install_message:
|
97
94
|
rdoc_options: []
|
98
95
|
require_paths:
|
99
96
|
- lib
|
100
97
|
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
-
none: false
|
102
98
|
requirements:
|
103
|
-
- -
|
99
|
+
- - ">="
|
104
100
|
- !ruby/object:Gem::Version
|
105
101
|
version: '0'
|
106
102
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
-
none: false
|
108
103
|
requirements:
|
109
|
-
- -
|
104
|
+
- - ">="
|
110
105
|
- !ruby/object:Gem::Version
|
111
106
|
version: '0'
|
112
107
|
requirements: []
|
113
108
|
rubyforge_project:
|
114
|
-
rubygems_version:
|
109
|
+
rubygems_version: 2.5.1
|
115
110
|
signing_key:
|
116
|
-
specification_version:
|
111
|
+
specification_version: 4
|
117
112
|
summary: stream zip files from rails
|
118
113
|
test_files:
|
119
114
|
- spec/lib/zipline/zip_generator_spec.rb
|
data/lib/zipline/fake_stream.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
#this is a class that acts like an IO::Stream, but really puts to the browser
|
2
|
-
module Zipline
|
3
|
-
class FakeStream
|
4
|
-
|
5
|
-
# &block is the block that each gets from rails... we pass it strings to send data
|
6
|
-
def initialize(&block)
|
7
|
-
@block = block
|
8
|
-
@pos = 0
|
9
|
-
end
|
10
|
-
|
11
|
-
def tell
|
12
|
-
@pos
|
13
|
-
end
|
14
|
-
|
15
|
-
def pos
|
16
|
-
@pos
|
17
|
-
end
|
18
|
-
|
19
|
-
def seek
|
20
|
-
throw :fit
|
21
|
-
end
|
22
|
-
|
23
|
-
def pos=
|
24
|
-
throw :fit
|
25
|
-
end
|
26
|
-
|
27
|
-
def to_s
|
28
|
-
throw :fit
|
29
|
-
end
|
30
|
-
|
31
|
-
def <<(x)
|
32
|
-
return if x.blank?
|
33
|
-
throw "bad class #{x.class}" unless x.class == String
|
34
|
-
@pos += x.bytesize
|
35
|
-
@block.call(x.to_s)
|
36
|
-
end
|
37
|
-
|
38
|
-
def close
|
39
|
-
nil
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
43
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
# a ZipOutputStream that never rewinds output
|
2
|
-
# in order for that to be possible we store only uncompressed files
|
3
|
-
module Zipline
|
4
|
-
class OutputStream < Zip::OutputStream
|
5
|
-
|
6
|
-
#we need to be able to hand out own custom output in order to stream to browser
|
7
|
-
def initialize(io)
|
8
|
-
# Create an io stream thing
|
9
|
-
super StringIO.new, true
|
10
|
-
# Overwrite it with my own
|
11
|
-
@output_stream = io
|
12
|
-
end
|
13
|
-
|
14
|
-
def stream
|
15
|
-
@output_stream
|
16
|
-
end
|
17
|
-
|
18
|
-
def put_next_entry(entry_name, size)
|
19
|
-
new_entry = Zip::Entry.new(@file_name, entry_name)
|
20
|
-
|
21
|
-
#THIS IS THE MAGIC, tells zip to look after data for size, crc
|
22
|
-
new_entry.gp_flags = new_entry.gp_flags | 0x0008
|
23
|
-
|
24
|
-
super(new_entry)
|
25
|
-
|
26
|
-
# Uncompressed size in the local file header must be zero when bit 3
|
27
|
-
# of the general purpose flags is set, so set the size after the header
|
28
|
-
# has been written.
|
29
|
-
new_entry.size = size
|
30
|
-
end
|
31
|
-
|
32
|
-
# just reset state, no rewinding required
|
33
|
-
def finalize_current_entry
|
34
|
-
if current_entry
|
35
|
-
entry = current_entry
|
36
|
-
super
|
37
|
-
write_local_footer(entry)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def write_local_footer(entry)
|
42
|
-
@output_stream << [ 0x08074b50, entry.crc, entry.compressed_size, entry.size].pack('VVVV')
|
43
|
-
end
|
44
|
-
|
45
|
-
#never need to do this because we set correct sizes up front
|
46
|
-
def update_local_headers
|
47
|
-
nil
|
48
|
-
end
|
49
|
-
|
50
|
-
# helper to deal with difference between rubyzip 1.0 and 1.1
|
51
|
-
def current_entry
|
52
|
-
@currentEntry || @current_entry
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|