zip_tricks 4.2.3 → 4.2.4
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/.gitignore +53 -0
- data/Gemfile +3 -13
- data/README.md +36 -0
- data/Rakefile +3 -48
- data/lib/zip_tricks.rb +0 -2
- data/lib/zip_tricks/block_deflate.rb +2 -0
- data/lib/zip_tricks/version.rb +3 -0
- data/lib/zip_tricks/zip_writer.rb +59 -13
- data/testing/README_TESTING.md +12 -0
- data/testing/generate_test_files.rb +86 -0
- data/testing/in/VTYL8830.jpg +0 -0
- data/{spec/zip_tricks → testing/in}/war-and-peace.txt +0 -0
- data/testing/support.rb +83 -0
- data/testing/test-report-2016-07-28.txt +156 -0
- data/testing/test-report-2016-12-12.txt +156 -0
- data/testing/test-report.txt +28 -0
- data/zip_tricks.gemspec +36 -109
- metadata +40 -65
- data/spec/spec_helper.rb +0 -91
- data/spec/zip_tricks/block_deflate_spec.rb +0 -111
- data/spec/zip_tricks/block_write_spec.rb +0 -95
- data/spec/zip_tricks/cdir_entry_with_partial_use_of_zip64_extra_fields.bin +0 -0
- data/spec/zip_tricks/file_reader_spec.rb +0 -287
- data/spec/zip_tricks/rack_body_spec.rb +0 -34
- data/spec/zip_tricks/remote_io_spec.rb +0 -125
- data/spec/zip_tricks/remote_uncap_spec.rb +0 -100
- data/spec/zip_tricks/size_estimator_spec.rb +0 -31
- data/spec/zip_tricks/stream_crc32_spec.rb +0 -38
- data/spec/zip_tricks/streamer/writable_spec.rb +0 -27
- data/spec/zip_tricks/streamer_spec.rb +0 -296
- data/spec/zip_tricks/write_and_tell_spec.rb +0 -43
- data/spec/zip_tricks/zip_writer_spec.rb +0 -419
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zip_tricks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.2.
|
4
|
+
version: 4.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julik Tarkhanov
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-03-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rubyzip
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -84,22 +98,22 @@ dependencies:
|
|
84
98
|
name: rspec
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
86
100
|
requirements:
|
87
|
-
- - "<"
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '3.3'
|
90
101
|
- - "~>"
|
91
102
|
- !ruby/object:Gem::Version
|
92
103
|
version: 3.2.0
|
104
|
+
- - "<"
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '3.3'
|
93
107
|
type: :development
|
94
108
|
prerelease: false
|
95
109
|
version_requirements: !ruby/object:Gem::Requirement
|
96
110
|
requirements:
|
97
|
-
- - "<"
|
98
|
-
- !ruby/object:Gem::Version
|
99
|
-
version: '3.3'
|
100
111
|
- - "~>"
|
101
112
|
- !ruby/object:Gem::Version
|
102
113
|
version: 3.2.0
|
114
|
+
- - "<"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '3.3'
|
103
117
|
- !ruby/object:Gem::Dependency
|
104
118
|
name: coderay
|
105
119
|
requirement: !ruby/object:Gem::Requirement
|
@@ -128,49 +142,15 @@ dependencies:
|
|
128
142
|
- - "~>"
|
129
143
|
- !ruby/object:Gem::Version
|
130
144
|
version: '0.8'
|
131
|
-
- !ruby/object:Gem::Dependency
|
132
|
-
name: bundler
|
133
|
-
requirement: !ruby/object:Gem::Requirement
|
134
|
-
requirements:
|
135
|
-
- - "~>"
|
136
|
-
- !ruby/object:Gem::Version
|
137
|
-
version: '1.0'
|
138
|
-
type: :development
|
139
|
-
prerelease: false
|
140
|
-
version_requirements: !ruby/object:Gem::Requirement
|
141
|
-
requirements:
|
142
|
-
- - "~>"
|
143
|
-
- !ruby/object:Gem::Version
|
144
|
-
version: '1.0'
|
145
|
-
- !ruby/object:Gem::Dependency
|
146
|
-
name: jeweler
|
147
|
-
requirement: !ruby/object:Gem::Requirement
|
148
|
-
requirements:
|
149
|
-
- - ">="
|
150
|
-
- !ruby/object:Gem::Version
|
151
|
-
version: 2.1.2
|
152
|
-
- - "~>"
|
153
|
-
- !ruby/object:Gem::Version
|
154
|
-
version: '2'
|
155
|
-
type: :development
|
156
|
-
prerelease: false
|
157
|
-
version_requirements: !ruby/object:Gem::Requirement
|
158
|
-
requirements:
|
159
|
-
- - ">="
|
160
|
-
- !ruby/object:Gem::Version
|
161
|
-
version: 2.1.2
|
162
|
-
- - "~>"
|
163
|
-
- !ruby/object:Gem::Version
|
164
|
-
version: '2'
|
165
145
|
description: Stream out ZIP files from Ruby
|
166
|
-
email:
|
146
|
+
email:
|
147
|
+
- me@julik.nl
|
167
148
|
executables: []
|
168
149
|
extensions: []
|
169
|
-
extra_rdoc_files:
|
170
|
-
- LICENSE.txt
|
171
|
-
- README.md
|
150
|
+
extra_rdoc_files: []
|
172
151
|
files:
|
173
152
|
- ".document"
|
153
|
+
- ".gitignore"
|
174
154
|
- ".rspec"
|
175
155
|
- ".travis.yml"
|
176
156
|
- ".yardopts"
|
@@ -200,28 +180,22 @@ files:
|
|
200
180
|
- lib/zip_tricks/streamer/entry.rb
|
201
181
|
- lib/zip_tricks/streamer/stored_writer.rb
|
202
182
|
- lib/zip_tricks/streamer/writable.rb
|
183
|
+
- lib/zip_tricks/version.rb
|
203
184
|
- lib/zip_tricks/write_and_tell.rb
|
204
185
|
- lib/zip_tricks/zip_writer.rb
|
205
|
-
-
|
206
|
-
-
|
207
|
-
-
|
208
|
-
-
|
209
|
-
-
|
210
|
-
-
|
211
|
-
-
|
212
|
-
-
|
213
|
-
- spec/zip_tricks/size_estimator_spec.rb
|
214
|
-
- spec/zip_tricks/stream_crc32_spec.rb
|
215
|
-
- spec/zip_tricks/streamer/writable_spec.rb
|
216
|
-
- spec/zip_tricks/streamer_spec.rb
|
217
|
-
- spec/zip_tricks/war-and-peace.txt
|
218
|
-
- spec/zip_tricks/write_and_tell_spec.rb
|
219
|
-
- spec/zip_tricks/zip_writer_spec.rb
|
186
|
+
- testing/README_TESTING.md
|
187
|
+
- testing/generate_test_files.rb
|
188
|
+
- testing/in/VTYL8830.jpg
|
189
|
+
- testing/in/war-and-peace.txt
|
190
|
+
- testing/support.rb
|
191
|
+
- testing/test-report-2016-07-28.txt
|
192
|
+
- testing/test-report-2016-12-12.txt
|
193
|
+
- testing/test-report.txt
|
220
194
|
- zip_tricks.gemspec
|
221
195
|
homepage: http://github.com/wetransfer/zip_tricks
|
222
|
-
licenses:
|
223
|
-
|
224
|
-
|
196
|
+
licenses: []
|
197
|
+
metadata:
|
198
|
+
allowed_push_host: https://rubygems.org
|
225
199
|
post_install_message:
|
226
200
|
rdoc_options: []
|
227
201
|
require_paths:
|
@@ -243,3 +217,4 @@ signing_key:
|
|
243
217
|
specification_version: 4
|
244
218
|
summary: Stream out ZIP files from Ruby
|
245
219
|
test_files: []
|
220
|
+
has_rdoc:
|
data/spec/spec_helper.rb
DELETED
@@ -1,91 +0,0 @@
|
|
1
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
-
|
4
|
-
require 'rspec'
|
5
|
-
require 'zip_tricks'
|
6
|
-
require 'digest'
|
7
|
-
require 'fileutils'
|
8
|
-
require 'shellwords'
|
9
|
-
require 'zip'
|
10
|
-
require 'delegate'
|
11
|
-
|
12
|
-
class ReadMonitor < SimpleDelegator
|
13
|
-
def read(*)
|
14
|
-
super.tap { @num_reads ||= 0; @num_reads += 1 }
|
15
|
-
end
|
16
|
-
|
17
|
-
def num_reads
|
18
|
-
@num_reads || 0
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
module Keepalive
|
23
|
-
# Travis-CI kills the build if it does not receive output on standard out or standard error
|
24
|
-
# for longer than a few minutes. We have a few tests that take a _very_ long time, and during
|
25
|
-
# those tests this method has to be called every now and then to revive the output and let the
|
26
|
-
# build proceed.
|
27
|
-
def still_alive!
|
28
|
-
$keepalive_last_out_ping_at ||= Time.now
|
29
|
-
if (Time.now - $keepalive_last_out_ping_at) > 3
|
30
|
-
$keepalive_last_out_ping_at = Time.now
|
31
|
-
$stdout << '_'
|
32
|
-
end
|
33
|
-
end
|
34
|
-
extend self
|
35
|
-
end
|
36
|
-
|
37
|
-
class ManagedTempfile < Tempfile
|
38
|
-
@@managed_tempfiles = []
|
39
|
-
|
40
|
-
def initialize(*)
|
41
|
-
super
|
42
|
-
@@managed_tempfiles << self
|
43
|
-
end
|
44
|
-
|
45
|
-
def self.prune!
|
46
|
-
@@managed_tempfiles.each do |tf|
|
47
|
-
(tf.close; tf.unlink) rescue nil
|
48
|
-
end
|
49
|
-
@@managed_tempfiles.clear
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
module ZipInspection
|
54
|
-
def inspect_zip_with_external_tool(path_to_zip)
|
55
|
-
zipinfo_path = 'zipinfo'
|
56
|
-
$zip_inspection_buf ||= StringIO.new
|
57
|
-
$zip_inspection_buf.puts "\n"
|
58
|
-
$zip_inspection_buf.puts "Inspecting ZIP output of #{inspect}." # The only way to get at the RSpec example without using the block argument
|
59
|
-
$zip_inspection_buf.puts "Be aware that the zipinfo version on OSX is too old to deal with Zip64."
|
60
|
-
escaped_cmd = Shellwords.join([zipinfo_path, '-tlhvz', path_to_zip])
|
61
|
-
$zip_inspection_buf.puts `#{escaped_cmd}`
|
62
|
-
end
|
63
|
-
|
64
|
-
def open_with_external_app(app_path, path_to_zip, skip_if_missing)
|
65
|
-
bin_exists = File.exist?(app_path)
|
66
|
-
skip "This system does not have #{File.basename(app_path)}" if skip_if_missing && !bin_exists
|
67
|
-
return unless bin_exists
|
68
|
-
`#{Shellwords.join([app_path, path_to_zip])}`
|
69
|
-
end
|
70
|
-
|
71
|
-
def open_zip_with_archive_utility(path_to_zip, skip_if_missing: false)
|
72
|
-
# ArchiveUtility sometimes puts the stuff it unarchives in ~/Downloads etc. so do
|
73
|
-
# not perform any checks on the files since we do not really know where they are on disk.
|
74
|
-
# Visual inspection should show whether the unarchiving is handled correctly.
|
75
|
-
au_path = '/System/Library/CoreServices/Applications/Archive Utility.app/Contents/MacOS/Archive Utility'
|
76
|
-
open_with_external_app(au_path, path_to_zip, skip_if_missing)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
RSpec.configure do |config|
|
81
|
-
config.include Keepalive
|
82
|
-
config.include ZipInspection
|
83
|
-
|
84
|
-
config.after :each do
|
85
|
-
ManagedTempfile.prune!
|
86
|
-
end
|
87
|
-
|
88
|
-
config.after :suite do
|
89
|
-
$stderr << $zip_inspection_buf.string if $zip_inspection_buf
|
90
|
-
end
|
91
|
-
end
|
@@ -1,111 +0,0 @@
|
|
1
|
-
require_relative '../spec_helper'
|
2
|
-
|
3
|
-
describe ZipTricks::BlockDeflate do
|
4
|
-
def tag_deflated(deflated_string, raw_string)
|
5
|
-
[120, 156].pack("C*") + deflated_string + [3,0].pack("C*") + [Zlib.adler32(raw_string)].pack("N")
|
6
|
-
end
|
7
|
-
|
8
|
-
describe '.deflate_chunk' do
|
9
|
-
it 'compresses a blob that can be inflated later, when the header, footer and adler32 are added' do
|
10
|
-
blob = 'compressible' * 1024 * 4
|
11
|
-
compressed = described_class.deflate_chunk(blob)
|
12
|
-
expect(compressed.bytesize).to be < blob.bytesize
|
13
|
-
complete_deflated_segment = tag_deflated(compressed, blob)
|
14
|
-
expect(Zlib.inflate(complete_deflated_segment)).to eq(blob)
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'removes the header' do
|
18
|
-
blob = 'compressible' * 1024 * 4
|
19
|
-
compressed = described_class.deflate_chunk(blob)
|
20
|
-
expect(compressed[0..1]).not_to eq([120, 156].pack("C*"))
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'removes the adler32' do
|
24
|
-
blob = 'compressible' * 1024 * 4
|
25
|
-
compressed = described_class.deflate_chunk(blob)
|
26
|
-
adler = [Zlib.adler32(blob)].pack("N")
|
27
|
-
expect(compressed).not_to end_with(adler)
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'removes the end marker' do
|
31
|
-
blob = 'compressible' * 1024 * 4
|
32
|
-
compressed = described_class.deflate_chunk(blob)
|
33
|
-
expect(compressed[-7..-5]).not_to eq([3,0].pack("C*"))
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'honors the compression level' do
|
37
|
-
deflater = Zlib::Deflate.new
|
38
|
-
expect(Zlib::Deflate).to receive(:new).with(2) { deflater }
|
39
|
-
blob = 'compressible' * 1024 * 4
|
40
|
-
compressed = described_class.deflate_chunk(blob, level: 2)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
describe 'deflate_in_blocks_and_terminate' do
|
45
|
-
it 'uses deflate_in_blocks' do
|
46
|
-
data = 'compressible' * 1024 * 1024 * 10
|
47
|
-
input = StringIO.new(data)
|
48
|
-
output = StringIO.new
|
49
|
-
block_size = 1024 * 64
|
50
|
-
expect(described_class).to receive(:deflate_in_blocks).with(input, output, level: -1, block_size: block_size).and_call_original
|
51
|
-
described_class.deflate_in_blocks_and_terminate(input, output, block_size: block_size)
|
52
|
-
end
|
53
|
-
|
54
|
-
it 'passes a custom compression level' do
|
55
|
-
data = 'compressible' * 1024 * 1024 * 10
|
56
|
-
input = StringIO.new(data)
|
57
|
-
output = StringIO.new
|
58
|
-
expect(described_class).to receive(:deflate_in_blocks).with(input, output, level: 9, block_size: 5242880).and_call_original
|
59
|
-
described_class.deflate_in_blocks_and_terminate(input, output, level: Zlib::BEST_COMPRESSION)
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'writes the end marker' do
|
63
|
-
data = 'compressible' * 1024 * 1024 * 10
|
64
|
-
input = StringIO.new(data)
|
65
|
-
output = StringIO.new
|
66
|
-
described_class.deflate_in_blocks_and_terminate(input, output)
|
67
|
-
expect(output.string[-2..-1]).to eq([3,0].pack("C*"))
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
describe '.write_terminator' do
|
72
|
-
it 'writes the terminator and returns 2 for number of bytes written' do
|
73
|
-
buf = double('IO')
|
74
|
-
expect(buf).to receive(:<<).with([3,0].pack("C*"))
|
75
|
-
expect(described_class.write_terminator(buf)).to eq(2)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
describe '.deflate_in_blocks' do
|
80
|
-
it 'honors the block size' do
|
81
|
-
data = 'compressible' * 1024 * 1024 * 10
|
82
|
-
input = StringIO.new(data)
|
83
|
-
output = StringIO.new
|
84
|
-
block_size = 1024 * 64
|
85
|
-
|
86
|
-
num_chunks = (data.bytesize / block_size.to_f).ceil
|
87
|
-
expect(described_class).to receive(:deflate_chunk).exactly(num_chunks).times.and_call_original
|
88
|
-
expect(input).to receive(:read).with(block_size).exactly(num_chunks + 1).times.and_call_original
|
89
|
-
expect(output).to receive(:<<).exactly(num_chunks).times.and_call_original
|
90
|
-
|
91
|
-
described_class.deflate_in_blocks(input, output, block_size: block_size)
|
92
|
-
end
|
93
|
-
|
94
|
-
it 'does not write the end marker' do
|
95
|
-
input_string = 'compressible' * 1024 * 1024 * 10
|
96
|
-
output_string = ''
|
97
|
-
|
98
|
-
described_class.deflate_in_blocks(StringIO.new(input_string), StringIO.new(output_string))
|
99
|
-
expect(output_string).not_to be_empty
|
100
|
-
expect(output_string).not_to end_with([3,0].pack("C*"))
|
101
|
-
end
|
102
|
-
|
103
|
-
it 'returns the number of bytes written' do
|
104
|
-
input_string = 'compressible' * 1024 * 1024 * 10
|
105
|
-
output_string = ''
|
106
|
-
|
107
|
-
num_bytes = described_class.deflate_in_blocks(StringIO.new(input_string), StringIO.new(output_string))
|
108
|
-
expect(num_bytes).to eq(245016)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
@@ -1,95 +0,0 @@
|
|
1
|
-
require_relative '../spec_helper'
|
2
|
-
|
3
|
-
describe ZipTricks::BlockWrite do
|
4
|
-
it 'calls the given block each time data is written' do
|
5
|
-
blobs = []
|
6
|
-
adapter = described_class.new{|s|
|
7
|
-
blobs << s
|
8
|
-
}
|
9
|
-
|
10
|
-
adapter << 'hello'
|
11
|
-
adapter << 'world'
|
12
|
-
adapter << '!'
|
13
|
-
|
14
|
-
expect(blobs).to eq(['hello', 'world', '!'])
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'supports chained shovel' do
|
18
|
-
blobs = []
|
19
|
-
adapter = described_class.new{|s|
|
20
|
-
blobs << s
|
21
|
-
}
|
22
|
-
|
23
|
-
adapter << 'hello' << 'world' << '!'
|
24
|
-
|
25
|
-
expect(blobs).to eq(['hello', 'world', '!'])
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'can write in all possible encodings, even if the strings are frozen' do
|
29
|
-
destination = ''.encode(Encoding::BINARY)
|
30
|
-
|
31
|
-
accum_string = ''
|
32
|
-
adapter = described_class.new{|s| accum_string << s }
|
33
|
-
|
34
|
-
adapter << 'hello'
|
35
|
-
adapter << 'привет'
|
36
|
-
adapter << 'привет'.freeze
|
37
|
-
adapter << '!'
|
38
|
-
adapter << SecureRandom.random_bytes(1024)
|
39
|
-
|
40
|
-
expect(accum_string.bytesize).to eq(1054)
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'can be closed' do
|
44
|
-
expect(described_class.new{}.close).to be_nil
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'forces the written strings to binary encoding' do
|
48
|
-
blobs = []
|
49
|
-
adapter = described_class.new{|s|
|
50
|
-
blobs << s
|
51
|
-
}
|
52
|
-
adapter << 'hello'.encode(Encoding::UTF_8)
|
53
|
-
adapter << 'world'.encode(Encoding::BINARY)
|
54
|
-
adapter << '!'
|
55
|
-
expect(blobs).not_to be_empty
|
56
|
-
blobs.each {|s| expect(s.encoding).to eq(Encoding::BINARY) }
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'omits strings of zero length' do
|
60
|
-
blobs = []
|
61
|
-
adapter = described_class.new{|s|
|
62
|
-
blobs << s
|
63
|
-
}
|
64
|
-
adapter << 'hello'
|
65
|
-
adapter << ''
|
66
|
-
adapter << '!'
|
67
|
-
expect(blobs).to eq(['hello', '!'])
|
68
|
-
end
|
69
|
-
|
70
|
-
it 'omits nils' do
|
71
|
-
blobs = []
|
72
|
-
adapter = described_class.new{|s|
|
73
|
-
blobs << s
|
74
|
-
}
|
75
|
-
adapter << 'hello'
|
76
|
-
adapter << nil
|
77
|
-
adapter << '!'
|
78
|
-
expect(blobs).to eq(['hello', '!'])
|
79
|
-
end
|
80
|
-
|
81
|
-
it 'raises a TypeError on specific unsupported methods' do
|
82
|
-
adapter = described_class.new {|s| }
|
83
|
-
expect {
|
84
|
-
adapter.seek(123)
|
85
|
-
}.to raise_error(/non\-rewindable/)
|
86
|
-
|
87
|
-
expect {
|
88
|
-
adapter.to_s
|
89
|
-
}.to raise_error(/non\-rewindable/)
|
90
|
-
|
91
|
-
expect {
|
92
|
-
adapter.pos = 123
|
93
|
-
}.to raise_error(/non\-rewindable/)
|
94
|
-
end
|
95
|
-
end
|