zip_tricks 5.0.0 → 5.1.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/.travis.yml +2 -6
- data/CHANGELOG.md +6 -0
- data/lib/zip_tricks/remote_io.rb +43 -24
- data/lib/zip_tricks/remote_uncap.rb +3 -29
- data/lib/zip_tricks/version.rb +1 -1
- data/zip_tricks.gemspec +2 -1
- metadata +22 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 983b83d36f88a25db8276a74e45d506f801ac3ecdd64197fd6fbc98bdb39cb03
|
4
|
+
data.tar.gz: c74a8a3936f4afb1f71ad7775025b73ccd04d2db309df8942a20ff64e82cea81
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b6eed391cd16c4077003535b0d7fb52e6930f351b230d31ba68aab2f05905df3987565aad76741083e888a91d054eaff3beab507117088b812b6c95f9ecf4f3
|
7
|
+
data.tar.gz: 9c4ad53ef462d28f8cdffcc439200788cb260e9d1b35ee231aed3b7979630d0c31881db95198a944c375c836678063e0db187fbfb3c2672819ad5e06d1023dc9
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## 5.1.0
|
2
|
+
|
3
|
+
* Slightly rework `RemoteIO` and `RemoteUncap` and make sure they work correctly by spinning up a test webserver
|
4
|
+
to verify their operation. The changes to the documented API are fairly small so this is still marked as a minor
|
5
|
+
release.
|
6
|
+
|
1
7
|
## 5.0.0
|
2
8
|
|
3
9
|
* Disable automatic filename deduplication by default, because it does not play nice with file/directory
|
data/lib/zip_tricks/remote_io.rb
CHANGED
@@ -8,14 +8,16 @@
|
|
8
8
|
# actual fetches over HTTP and an object that expects a handful of IO methods to be
|
9
9
|
# available.
|
10
10
|
class ZipTricks::RemoteIO
|
11
|
-
# @param
|
12
|
-
def initialize(
|
11
|
+
# @param url[String, URI] the HTTP/HTTPS URL of the object to be retrieved
|
12
|
+
def initialize(url)
|
13
13
|
@pos = 0
|
14
|
-
@
|
15
|
-
@remote_size =
|
14
|
+
@uri = URI(url)
|
15
|
+
@remote_size = nil
|
16
16
|
end
|
17
17
|
|
18
18
|
# Emulates IO#seek
|
19
|
+
# @param offset[Integer] absolute offset in the remote resource to seek to
|
20
|
+
# @param mode[Integer] The seek mode (only SEEK_SET is supported)
|
19
21
|
def seek(offset, mode = IO::SEEK_SET)
|
20
22
|
raise "Unsupported read mode #{mode}" unless mode == IO::SEEK_SET
|
21
23
|
@remote_size ||= request_object_size
|
@@ -25,7 +27,7 @@ class ZipTricks::RemoteIO
|
|
25
27
|
|
26
28
|
# Emulates IO#size.
|
27
29
|
#
|
28
|
-
# @return [
|
30
|
+
# @return [Integer] the size of the remote resource
|
29
31
|
def size
|
30
32
|
@remote_size ||= request_object_size
|
31
33
|
end
|
@@ -39,21 +41,20 @@ class ZipTricks::RemoteIO
|
|
39
41
|
# @param n_bytes[Fixnum, nil] how many bytes to read, or `nil` to read all the way to the end
|
40
42
|
# @return [String] the read bytes
|
41
43
|
def read(n_bytes = nil)
|
42
|
-
@remote_size ||= request_object_size
|
43
|
-
|
44
44
|
# If the resource is empty there is nothing to read
|
45
|
-
return if
|
45
|
+
return if size.zero?
|
46
46
|
|
47
|
-
maximum_avaialable =
|
47
|
+
maximum_avaialable = size - @pos
|
48
48
|
n_bytes ||= maximum_avaialable # nil == read to the end of file
|
49
49
|
return '' if n_bytes.zero?
|
50
50
|
raise ArgumentError, "No negative reads(#{n_bytes})" if n_bytes < 0
|
51
51
|
|
52
52
|
n_bytes = clamp(0, n_bytes, maximum_avaialable)
|
53
53
|
|
54
|
-
|
54
|
+
http_range = (@pos..(@pos + n_bytes - 1))
|
55
|
+
request_range(http_range).tap do |data|
|
55
56
|
raise "Remote read returned #{data.bytesize} bytes instead of #{n_bytes} as requested" if data.bytesize != n_bytes
|
56
|
-
@pos = clamp(0, @pos + data.bytesize,
|
57
|
+
@pos = clamp(0, @pos + data.bytesize, size)
|
57
58
|
end
|
58
59
|
end
|
59
60
|
|
@@ -66,23 +67,41 @@ class ZipTricks::RemoteIO
|
|
66
67
|
|
67
68
|
protected
|
68
69
|
|
70
|
+
# Only used internally when reading the remote ZIP.
|
71
|
+
#
|
72
|
+
# @param range[Range] the HTTP range of data to fetch from remote
|
73
|
+
# @return [String] the response body of the ranged request
|
69
74
|
def request_range(range)
|
70
|
-
@
|
75
|
+
http = Net::HTTP.start(@uri.hostname, @uri.port)
|
76
|
+
request = Net::HTTP::Get.new(@uri)
|
77
|
+
request.range = range
|
78
|
+
response = http.request(request)
|
79
|
+
case response.code
|
80
|
+
when "206", "200"
|
81
|
+
response.body
|
82
|
+
else
|
83
|
+
raise "Remote at #{@uri} replied with code #{response.code}"
|
84
|
+
end
|
71
85
|
end
|
72
86
|
|
87
|
+
# For working with S3 it is a better idea to perform a GET request for one byte, since doing a HEAD
|
88
|
+
# request needs a different permission - and standard GET presigned URLs are not allowed to perform it
|
89
|
+
#
|
90
|
+
# @return [Integer] the size of the remote resource, parsed either from Content-Length or Content-Range header
|
73
91
|
def request_object_size
|
74
|
-
@
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
92
|
+
http = Net::HTTP.start(@uri.hostname, @uri.port)
|
93
|
+
request = Net::HTTP::Get.new(@uri)
|
94
|
+
request.range = 0..0
|
95
|
+
response = http.request(request)
|
96
|
+
case response.code
|
97
|
+
when "206"
|
98
|
+
content_range_header_value = response['Content-Range']
|
99
|
+
content_range_header_value.split('/').last.to_i
|
100
|
+
when "200"
|
101
|
+
response['Content-Length'].to_i
|
102
|
+
else
|
103
|
+
raise "Remote at #{@uri} replied with code #{response.code}"
|
104
|
+
end
|
86
105
|
end
|
87
106
|
|
88
107
|
private
|
@@ -7,42 +7,16 @@
|
|
7
7
|
#
|
8
8
|
# Please read the security warning in `FileReader` _VERY CAREFULLY_
|
9
9
|
# before you use this module.
|
10
|
-
|
10
|
+
module ZipTricks::RemoteUncap
|
11
11
|
# @param uri[String] the HTTP(S) URL to read the ZIP footer from
|
12
12
|
# @param reader_class[Class] which class to use for reading
|
13
13
|
# @param options_for_zip_reader[Hash] any additional options to give to
|
14
14
|
# {ZipTricks::FileReader} when reading
|
15
15
|
# @return [Array<ZipTricks::FileReader::ZipEntry>] metadata about the
|
16
16
|
# files within the remote archive
|
17
|
-
def self.files_within_zip_at(uri,
|
18
|
-
|
19
|
-
**options_for_zip_reader)
|
20
|
-
fetcher = new(uri)
|
21
|
-
fake_io = ZipTricks::RemoteIO.new(fetcher)
|
17
|
+
def self.files_within_zip_at(uri, reader_class: ZipTricks::FileReader, **options_for_zip_reader)
|
18
|
+
fake_io = ZipTricks::RemoteIO.new(uri)
|
22
19
|
reader = reader_class.new
|
23
20
|
reader.read_zip_structure(io: fake_io, **options_for_zip_reader)
|
24
21
|
end
|
25
|
-
|
26
|
-
def initialize(uri)
|
27
|
-
@uri = URI(uri)
|
28
|
-
end
|
29
|
-
|
30
|
-
# Only used internally when reading the remote ZIP.
|
31
|
-
#
|
32
|
-
# @param range[Range] the HTTP range of data to fetch from remote
|
33
|
-
# @return [String] the response body of the ranged request
|
34
|
-
def request_range(range)
|
35
|
-
request = Net::HTTP::Get.new(@uri)
|
36
|
-
request.range = range
|
37
|
-
http = Net::HTTP.start(@uri.hostname, @uri.port)
|
38
|
-
http.request(request).body
|
39
|
-
end
|
40
|
-
|
41
|
-
# Only used internally when reading the remote ZIP.
|
42
|
-
#
|
43
|
-
# @return [Fixnum] the byte size of the ranged request
|
44
|
-
def request_object_size
|
45
|
-
http = Net::HTTP.start(@uri.hostname, @uri.port)
|
46
|
-
http.request_head(@uri)['Content-Length'].to_i
|
47
|
-
end
|
48
22
|
end
|
data/lib/zip_tricks/version.rb
CHANGED
data/zip_tricks.gemspec
CHANGED
@@ -31,7 +31,7 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.require_paths = ['lib']
|
32
32
|
|
33
33
|
spec.add_development_dependency 'bundler'
|
34
|
-
spec.add_development_dependency 'rubyzip', '>= 1.2.2'
|
34
|
+
spec.add_development_dependency 'rubyzip', '~> 1', '>= 1.2.2'
|
35
35
|
spec.add_development_dependency 'terminal-table'
|
36
36
|
spec.add_development_dependency 'range_utils'
|
37
37
|
|
@@ -44,4 +44,5 @@ Gem::Specification.new do |spec|
|
|
44
44
|
spec.add_development_dependency 'allocation_stats', '~> 0.1.5'
|
45
45
|
spec.add_development_dependency 'yard', '~> 0.9'
|
46
46
|
spec.add_development_dependency 'wetransfer_style', '0.6.0'
|
47
|
+
spec.add_development_dependency 'puma'
|
47
48
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zip_tricks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julik Tarkhanov
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: exe
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2020-02-04 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -31,6 +31,9 @@ dependencies:
|
|
31
31
|
name: rubyzip
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
requirements:
|
34
|
+
- - "~>"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '1'
|
34
37
|
- - ">="
|
35
38
|
- !ruby/object:Gem::Version
|
36
39
|
version: 1.2.2
|
@@ -38,6 +41,9 @@ dependencies:
|
|
38
41
|
prerelease: false
|
39
42
|
version_requirements: !ruby/object:Gem::Requirement
|
40
43
|
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1'
|
41
47
|
- - ">="
|
42
48
|
- !ruby/object:Gem::Version
|
43
49
|
version: 1.2.2
|
@@ -195,6 +201,20 @@ dependencies:
|
|
195
201
|
- - '='
|
196
202
|
- !ruby/object:Gem::Version
|
197
203
|
version: 0.6.0
|
204
|
+
- !ruby/object:Gem::Dependency
|
205
|
+
name: puma
|
206
|
+
requirement: !ruby/object:Gem::Requirement
|
207
|
+
requirements:
|
208
|
+
- - ">="
|
209
|
+
- !ruby/object:Gem::Version
|
210
|
+
version: '0'
|
211
|
+
type: :development
|
212
|
+
prerelease: false
|
213
|
+
version_requirements: !ruby/object:Gem::Requirement
|
214
|
+
requirements:
|
215
|
+
- - ">="
|
216
|
+
- !ruby/object:Gem::Version
|
217
|
+
version: '0'
|
198
218
|
description: Stream out ZIP files from Ruby
|
199
219
|
email:
|
200
220
|
- me@julik.nl
|