Compare commits
38 Commits
Author | SHA1 | Date |
---|---|---|
|
6c4b7a9f90 | |
|
3b4c2bfa22 | |
|
e3eb62491b | |
|
c09352b546 | |
|
71bb069049 | |
|
bb06f99b14 | |
|
3d95a8204f | |
|
56954b0b59 | |
|
6ff40f7a78 | |
|
e05dc9b978 | |
|
a4c3f5bddb | |
|
57cff3338f | |
|
0001864cfe | |
|
385ebd054a | |
|
46689d7350 | |
|
ef89a62b70 | |
|
900db76760 | |
|
14efdd1cc4 | |
|
02faddaf44 | |
|
9aa5964262 | |
|
13f4ea766f | |
|
3910870f3a | |
|
07d833ca78 | |
|
6bbda380fe | |
|
a6e6c3c469 | |
|
b691a4b72c | |
|
f68877920a | |
|
13781b20d3 | |
|
4b1cfba9db | |
|
5e9ee53c70 | |
|
cb0505d735 | |
|
49950d924c | |
|
a17da19e0c | |
|
7c1a8fbf8f | |
|
77611045f1 | |
|
2f1c1ea400 | |
|
16de339666 | |
|
84d7a66abc |
|
@ -0,0 +1,81 @@
|
|||
name: Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu]
|
||||
ruby: ['2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2', '3.3', '3.4', head, jruby, truffleruby]
|
||||
include:
|
||||
- os: macos
|
||||
ruby: '2.6'
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
continue-on-error: ${{ endsWith(matrix.ruby, 'head') }}
|
||||
steps:
|
||||
- name: Checkout rubyzip code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install and set up ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
rubygems: '3.2.3'
|
||||
bundler-cache: true
|
||||
|
||||
- name: Run the tests
|
||||
env:
|
||||
RUBYOPT: -v
|
||||
JRUBY_OPTS: --debug
|
||||
FULL_ZIP64_TEST: 1
|
||||
run: bundle exec rake
|
||||
|
||||
test-frozen-string-literal:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu]
|
||||
ruby: ['3.3', '3.4', head]
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- name: Checkout rubyzip code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install and set up ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
bundler-cache: true
|
||||
|
||||
- name: Run the tests
|
||||
env:
|
||||
RUBYOPT: --enable-frozen-string-literal
|
||||
FULL_ZIP64_TEST: 1
|
||||
run: bundle exec rake
|
||||
|
||||
test-yjit:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu, macos]
|
||||
ruby: ['3.1', '3.2', '3.3', '3.4', head]
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- name: Checkout rubyzip code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install and set up ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
bundler-cache: true
|
||||
|
||||
- name: Run the tests
|
||||
env:
|
||||
RUBYOPT: --enable-yjit -v
|
||||
FULL_ZIP64_TEST: 1
|
||||
run: bundle exec rake
|
|
@ -23,11 +23,6 @@ Lint/SuppressedException:
|
|||
Exclude:
|
||||
- 'test/**/*.rb'
|
||||
|
||||
# Allow this "useless" test, as we are testing <=> here.
|
||||
Lint/UselessComparison:
|
||||
Exclude:
|
||||
- 'test/entry_test.rb'
|
||||
|
||||
# Turn off ABC metrics for the tests and set a workable max given
|
||||
# the current state of the code.
|
||||
Metrics/AbcSize:
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
# Offense count: 15
|
||||
# Configuration parameters: CountComments.
|
||||
Metrics/ClassLength:
|
||||
Max: 580
|
||||
Max: 600
|
||||
|
||||
# Offense count: 26
|
||||
Metrics/CyclomaticComplexity:
|
||||
|
@ -18,7 +18,7 @@ Metrics/CyclomaticComplexity:
|
|||
# Offense count: 120
|
||||
# Configuration parameters: CountComments, ExcludedMethods.
|
||||
Metrics/MethodLength:
|
||||
Max: 30
|
||||
Max: 32
|
||||
|
||||
# Offense count: 2
|
||||
# Configuration parameters: CountKeywordArgs.
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
require 'coveralls'
|
||||
|
||||
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
|
||||
SimpleCov::Formatter::HTMLFormatter,
|
||||
Coveralls::SimpleCov::Formatter
|
||||
])
|
||||
SimpleCov.start do
|
||||
add_filter '/test'
|
||||
end
|
34
.travis.yml
34
.travis.yml
|
@ -1,34 +0,0 @@
|
|||
language: ruby
|
||||
dist: xenial
|
||||
cache: bundler
|
||||
rvm:
|
||||
- 2.4
|
||||
- 2.5
|
||||
- 2.6
|
||||
- 2.7
|
||||
- ruby-head
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- rvm: jruby-9.2
|
||||
jdk: openjdk8
|
||||
- rvm: jruby-9.2
|
||||
jdk: openjdk11
|
||||
- rvm: jruby-head
|
||||
jdk: openjdk11
|
||||
- rvm: rbx-4
|
||||
allow_failures:
|
||||
- rvm: ruby-head
|
||||
- rvm: rbx-4
|
||||
- rvm: jruby-head
|
||||
before_install:
|
||||
- gem --version
|
||||
before_script:
|
||||
- echo `whereis zip`
|
||||
- echo `whereis unzip`
|
||||
env:
|
||||
global:
|
||||
- JRUBY_OPTS="--debug"
|
||||
- COVERALLS_PARALLEL=true
|
||||
notifications:
|
||||
webhooks: https://coveralls.io/webhook
|
31
Changelog.md
31
Changelog.md
|
@ -1,5 +1,36 @@
|
|||
# X.X.X (Next)
|
||||
|
||||
# 2.4.1 (2025-01-05)
|
||||
|
||||
*This is a re-release of version 2.4 with a full version number string. We need to move to version 2.4.1 due to the canonical version number 2.4 now being taken in Rubygems.*
|
||||
|
||||
Tooling:
|
||||
|
||||
- Opt-in for MFA requirement explicitly on 2.4 branch.
|
||||
|
||||
# 2.4 (2025-01-04) - Yanked
|
||||
|
||||
*Yanked due to incorrect version number format (2.4 vs 2.4.0).*
|
||||
|
||||
- Ensure compatibility with `--enable-frozen-string-literal`.
|
||||
- Ensure `File.open_buffer` doesn't rewrite unchanged data. This is a backport of the fix on the 3.x branch.
|
||||
- Enable use of the version 3 calling style (mainly named parameters) wherever possible, while retaining version 2.x compatibility.
|
||||
- Add (switchable) warning messages to methods that are changed or removed in version 3.x.
|
||||
|
||||
Tooling:
|
||||
|
||||
- Switch to using GitHub Actions (from Travis).
|
||||
- Update Rubocop versions and configuration.
|
||||
- Update actions with latest rubies.
|
||||
|
||||
# 2.3.2 (2021-07-05)
|
||||
|
||||
- This is a dummy release to warn about breaking changes coming in version 3.0. This updated version uses the Gem `post_install_message` instead of printing to `STDERR`.
|
||||
|
||||
# 2.3.1 (2021-07-03)
|
||||
|
||||
- This is a dummy release to warn about breaking changes coming in version 3.0.
|
||||
|
||||
# 2.3.0 (2020-03-14)
|
||||
|
||||
- Fix frozen string literal error [#431](https://github.com/rubyzip/rubyzip/pull/431)
|
||||
|
|
26
README.md
26
README.md
|
@ -1,7 +1,7 @@
|
|||
# rubyzip
|
||||
|
||||
[](http://badge.fury.io/rb/rubyzip)
|
||||
[](http://travis-ci.org/rubyzip/rubyzip)
|
||||
[](https://github.com/rubyzip/rubyzip/actions/workflows/tests.yml)
|
||||
[](https://codeclimate.com/github/rubyzip/rubyzip)
|
||||
[](https://coveralls.io/r/rubyzip/rubyzip?branch=master)
|
||||
|
||||
|
@ -9,18 +9,26 @@ Rubyzip is a ruby library for reading and writing zip files.
|
|||
|
||||
## Important note
|
||||
|
||||
The Rubyzip interface has changed!!! No need to do `require "zip/zip"` and `Zip` prefix in class names removed.
|
||||
Rubyzip 2.4 is intended to be the last release in the 2.x series. Please get ready for version 3.0.
|
||||
|
||||
If you have issues with any third-party gems that require an old version of rubyzip, you can use this workaround:
|
||||
### Updating to version 3.0
|
||||
|
||||
```ruby
|
||||
gem 'rubyzip', '>= 1.0.0' # will load new rubyzip version
|
||||
gem 'zip-zip' # will load compatibility for old rubyzip API.
|
||||
```
|
||||
The public API of some classes has been modernized to use named parameters for optional arguments. Also some methods have been changed or removed. Please check your usage of the following Rubyzip classes:
|
||||
* `File`
|
||||
* `Entry`
|
||||
* `InputStream`
|
||||
* `OutputStream`
|
||||
* `DOSTime`
|
||||
|
||||
**Please see [Updating to version 3.x](https://github.com/rubyzip/rubyzip/wiki/Updating-to-version-3.x) in the wiki for details.**
|
||||
|
||||
## Requirements
|
||||
|
||||
- Ruby 2.4 or greater (for rubyzip 2.0; use 1.x for older rubies)
|
||||
Version 3.x requires at least Ruby 3.0.
|
||||
|
||||
Version 2.x requires at least Ruby 2.4, and is known to work on Ruby 3.x.
|
||||
|
||||
It is not recommended to use any versions of Rubyzip earlier than 2.3 due to security issues.
|
||||
|
||||
## Installation
|
||||
|
||||
|
@ -188,7 +196,7 @@ If `::Zip::InputStream` finds such entry in the zip archive it will raise an exc
|
|||
Rubyzip supports reading/writing zip files with traditional zip encryption (a.k.a. "ZipCrypto"). AES encryption is not yet supported. It can be used with buffer streams, e.g.:
|
||||
|
||||
```ruby
|
||||
Zip::OutputStream.write_buffer(::StringIO.new(''), Zip::TraditionalEncrypter.new('password')) do |out|
|
||||
Zip::OutputStream.write_buffer(::StringIO.new, Zip::TraditionalEncrypter.new('password')) do |out|
|
||||
out.put_next_entry("my_file.txt")
|
||||
out.write my_data
|
||||
end.string
|
||||
|
|
19
lib/zip.rb
19
lib/zip.rb
|
@ -34,6 +34,25 @@ require 'zip/streamable_directory'
|
|||
require 'zip/errors'
|
||||
|
||||
module Zip
|
||||
V3_API_WARNING_MSG = <<~END_MSG
|
||||
You have called '%s' (from %s).
|
||||
This method is changing or deprecated in version 3.0.0. Please see
|
||||
https://github.com/rubyzip/rubyzip/wiki/Updating-to-version-3.x
|
||||
for more information.
|
||||
END_MSG
|
||||
|
||||
def self.warn_about_v3_api(method)
|
||||
return unless ENV['RUBYZIP_V3_API_WARN']
|
||||
|
||||
loc = caller_locations(2, 1)[0]
|
||||
from = "#{loc.path.split('/').last}:#{loc.lineno}"
|
||||
warn format(V3_API_WARNING_MSG, method, from)
|
||||
end
|
||||
|
||||
if ENV['RUBYZIP_V3_API_WARN'] && RUBY_VERSION < '3.0'
|
||||
warn 'RubyZip 3.0 will require Ruby 3.0 or later.'
|
||||
end
|
||||
|
||||
extend self
|
||||
attr_accessor :unicode_names,
|
||||
:on_exists_proc,
|
||||
|
|
|
@ -24,9 +24,17 @@ module Zip
|
|||
((year - 1980) << 9)
|
||||
end
|
||||
|
||||
# Dos time is only stored with two seconds accuracy
|
||||
def dos_equals(other)
|
||||
to_i / 2 == other.to_i / 2
|
||||
Zip.warn_about_v3_api('DOSTime#dos_equals')
|
||||
|
||||
self == other
|
||||
end
|
||||
|
||||
# Dos time is only stored with two seconds accuracy.
|
||||
def <=>(other)
|
||||
return unless other.kind_of?(Time)
|
||||
|
||||
(to_i / 2) <=> (other.to_i / 2)
|
||||
end
|
||||
|
||||
# Create a DOSTime instance from a vanilla Time instance.
|
||||
|
@ -41,9 +49,8 @@ module Zip
|
|||
day = (0b11111 & bin_dos_date)
|
||||
month = (0b111100000 & bin_dos_date) >> 5
|
||||
year = ((0b1111111000000000 & bin_dos_date) >> 9) + 1980
|
||||
begin
|
||||
local(year, month, day, hour, minute, second)
|
||||
end
|
||||
|
||||
local(year, month, day, hour, minute, second)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -52,26 +52,41 @@ module Zip
|
|||
raise ::Zip::EntryNameError, "Illegal ZipEntry name '#{name}', name must not start with /"
|
||||
end
|
||||
|
||||
def initialize(*args)
|
||||
name = args[1] || ''
|
||||
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
||||
def initialize(zipfile = nil, name = nil, *args)
|
||||
name ||= ''
|
||||
check_name(name)
|
||||
|
||||
set_default_vars_values
|
||||
@fstype = ::Zip::RUNNING_ON_WINDOWS ? ::Zip::FSTYPE_FAT : ::Zip::FSTYPE_UNIX
|
||||
|
||||
@zipfile = args[0] || ''
|
||||
@zipfile = zipfile || ''
|
||||
@name = name
|
||||
@comment = args[2] || ''
|
||||
@extra = args[3] || ''
|
||||
@compressed_size = args[4] || 0
|
||||
@crc = args[5] || 0
|
||||
@compression_method = args[6] || ::Zip::Entry::DEFLATED
|
||||
@size = args[7] || 0
|
||||
@time = args[8] || ::Zip::DOSTime.now
|
||||
|
||||
if (args_hash = args.first).kind_of?(::Hash)
|
||||
@comment = args_hash[:comment] || ''
|
||||
@extra = args_hash[:extra] || ''
|
||||
@compressed_size = args_hash[:compressed_size] || 0
|
||||
@crc = args_hash[:crc] || 0
|
||||
@compression_method = args_hash[:compression_method] || ::Zip::Entry::DEFLATED
|
||||
@size = args_hash[:size] || 0
|
||||
@time = args_hash[:time] || ::Zip::DOSTime.now
|
||||
else
|
||||
Zip.warn_about_v3_api('Zip::Entry.new') unless args.empty?
|
||||
|
||||
@comment = args[0] || ''
|
||||
@extra = args[1] || ''
|
||||
@compressed_size = args[2] || 0
|
||||
@crc = args[3] || 0
|
||||
@compression_method = args[4] || ::Zip::Entry::DEFLATED
|
||||
@size = args[5] || 0
|
||||
@time = args[6] || ::Zip::DOSTime.now
|
||||
end
|
||||
|
||||
@ftype = name_is_directory? ? :directory : :file
|
||||
@extra = ::Zip::ExtraField.new(@extra.to_s) unless @extra.kind_of?(::Zip::ExtraField)
|
||||
end
|
||||
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
||||
|
||||
def encrypted?
|
||||
gp_flags & 1 == 1
|
||||
|
@ -174,6 +189,8 @@ module Zip
|
|||
# NB: The caller is responsible for making sure dest_path is safe, if it
|
||||
# is passed.
|
||||
def extract(dest_path = nil, &block)
|
||||
Zip.warn_about_v3_api('Zip::Entry#extract')
|
||||
|
||||
if dest_path.nil? && !name_safe?
|
||||
warn "WARNING: skipped '#{@name}' as unsafe."
|
||||
return self
|
||||
|
@ -188,6 +205,28 @@ module Zip
|
|||
self
|
||||
end
|
||||
|
||||
# Extracts this entry to a file at `entry_path`, with
|
||||
# `destination_directory` as the base location in the filesystem.
|
||||
#
|
||||
# NB: The caller is responsible for making sure `destination_directory` is
|
||||
# safe, if it is passed.
|
||||
def extract_v3(entry_path = @name, destination_directory: '.', &block)
|
||||
dest_dir = ::File.absolute_path(destination_directory || '.')
|
||||
extract_path = ::File.absolute_path(::File.join(dest_dir, entry_path))
|
||||
|
||||
unless extract_path.start_with?(dest_dir)
|
||||
warn "WARNING: skipped extracting '#{@name}' to '#{extract_path}' as unsafe."
|
||||
return self
|
||||
end
|
||||
|
||||
block ||= proc { ::Zip.on_exists_proc }
|
||||
|
||||
raise "unknown file type #{inspect}" unless directory? || file? || symlink?
|
||||
|
||||
__send__(:"create_#{ftype}", extract_path, &block)
|
||||
self
|
||||
end
|
||||
|
||||
def to_s
|
||||
@name
|
||||
end
|
||||
|
@ -506,7 +545,7 @@ module Zip
|
|||
keys_equal = %w[compression_method crc compressed_size size name extra filepath].all? do |k|
|
||||
other.__send__(k.to_sym) == __send__(k.to_sym)
|
||||
end
|
||||
keys_equal && time.dos_equals(other.time)
|
||||
keys_equal && time == other.time
|
||||
end
|
||||
|
||||
def <=>(other)
|
||||
|
@ -532,7 +571,7 @@ module Zip
|
|||
raise "unknown @file_type #{@ftype}"
|
||||
end
|
||||
else
|
||||
zis = ::Zip::InputStream.new(@zipfile, local_header_offset)
|
||||
zis = ::Zip::InputStream.new(@zipfile, offset: local_header_offset)
|
||||
zis.instance_variable_set(:@complete_entry, self)
|
||||
zis.get_next_entry
|
||||
if block_given?
|
||||
|
|
|
@ -51,7 +51,7 @@ module Zip
|
|||
# reserved 0 and tag 1
|
||||
s = [0, 1].pack('Vv')
|
||||
|
||||
tag1 = ''.force_encoding(Encoding::BINARY)
|
||||
tag1 = ''.b
|
||||
if @mtime
|
||||
tag1 << [to_ntfs_time(@mtime)].pack('Q<')
|
||||
if @atime
|
||||
|
|
|
@ -59,7 +59,7 @@ module Zip
|
|||
|
||||
def pack_for_c_dir
|
||||
# central directory entries contain only fields that didn't fit in the main entry part
|
||||
packed = ''.force_encoding('BINARY')
|
||||
packed = ''.b
|
||||
packed << [@original_size].pack('Q<') if @original_size
|
||||
packed << [@compressed_size].pack('Q<') if @compressed_size
|
||||
packed << [@relative_header_offset].pack('Q<') if @relative_header_offset
|
||||
|
|
|
@ -73,12 +73,17 @@ module Zip
|
|||
|
||||
# Opens a zip archive. Pass true as the second parameter to create
|
||||
# a new archive if it doesn't exist already.
|
||||
def initialize(path_or_io, create = false, buffer = false, options = {})
|
||||
def initialize(path_or_io, dep_create = false, dep_buffer = false,
|
||||
create: false, buffer: false, **options)
|
||||
super()
|
||||
|
||||
Zip.warn_about_v3_api('File#new') if dep_create || dep_buffer
|
||||
|
||||
options = DEFAULT_OPTIONS.merge(options)
|
||||
@name = path_or_io.respond_to?(:path) ? path_or_io.path : path_or_io
|
||||
@comment = ''
|
||||
@create = create ? true : false # allow any truthy value to mean true
|
||||
@create = create || dep_create ? true : false # allow any truthy value to mean true
|
||||
buffer ||= dep_buffer
|
||||
|
||||
if ::File.size?(@name.to_s)
|
||||
# There is a file, which exists, that is associated with this zip.
|
||||
|
@ -94,6 +99,7 @@ module Zip
|
|||
end
|
||||
elsif buffer && path_or_io.size > 0
|
||||
# This zip is probably a non-empty StringIO.
|
||||
@create = false
|
||||
read_from_stream(path_or_io)
|
||||
elsif @create
|
||||
# This zip is completely new/empty and is to be created.
|
||||
|
@ -117,8 +123,10 @@ module Zip
|
|||
# Similar to ::new. If a block is passed the Zip::File object is passed
|
||||
# to the block and is automatically closed afterwards, just as with
|
||||
# ruby's builtin File::open method.
|
||||
def open(file_name, create = false, options = {})
|
||||
zf = ::Zip::File.new(file_name, create, false, options)
|
||||
def open(file_name, dep_create = false, create: false, **options)
|
||||
Zip.warn_about_v3_api('Zip::File.open') if dep_create
|
||||
|
||||
zf = ::Zip::File.new(file_name, create: (dep_create || create), buffer: false, **options)
|
||||
return zf unless block_given?
|
||||
|
||||
begin
|
||||
|
@ -130,7 +138,9 @@ module Zip
|
|||
|
||||
# Same as #open. But outputs data to a buffer instead of a file
|
||||
def add_buffer
|
||||
io = ::StringIO.new('')
|
||||
Zip.warn_about_v3_api('Zip::File.add_buffer')
|
||||
|
||||
io = ::StringIO.new
|
||||
zf = ::Zip::File.new(io, true, true)
|
||||
yield zf
|
||||
zf.write_buffer(io)
|
||||
|
@ -140,7 +150,7 @@ module Zip
|
|||
# stream, and outputs data to a buffer.
|
||||
# (This can be used to extract data from a
|
||||
# downloaded zip archive without first saving it to disk.)
|
||||
def open_buffer(io, options = {})
|
||||
def open_buffer(io, **options)
|
||||
unless IO_METHODS.map { |method| io.respond_to?(method) }.all? || io.kind_of?(String)
|
||||
raise "Zip::File.open_buffer expects a String or IO-like argument (responds to #{IO_METHODS.join(', ')}). Found: #{io.class}"
|
||||
end
|
||||
|
@ -150,7 +160,7 @@ module Zip
|
|||
# https://github.com/rubyzip/rubyzip/issues/119
|
||||
io.binmode if io.respond_to?(:binmode)
|
||||
|
||||
zf = ::Zip::File.new(io, true, true, options)
|
||||
zf = ::Zip::File.new(io, create: true, buffer: true, **options)
|
||||
return zf unless block_given?
|
||||
|
||||
yield zf
|
||||
|
@ -228,18 +238,24 @@ module Zip
|
|||
end
|
||||
|
||||
# Splits an archive into parts with segment size
|
||||
def split(zip_file_name, segment_size = MAX_SEGMENT_SIZE, delete_zip_file = true, partial_zip_file_name = nil)
|
||||
def split(zip_file_name,
|
||||
dep_segment_size = MAX_SEGMENT_SIZE, dep_delete_zip_file = true, dep_partial_zip_file_name = nil,
|
||||
segment_size: MAX_SEGMENT_SIZE, delete_zip_file: nil, partial_zip_file_name: nil)
|
||||
raise Error, "File #{zip_file_name} not found" unless ::File.exist?(zip_file_name)
|
||||
raise Errno::ENOENT, zip_file_name unless ::File.readable?(zip_file_name)
|
||||
|
||||
if dep_segment_size != MAX_SEGMENT_SIZE || !dep_delete_zip_file || dep_partial_zip_file_name
|
||||
Zip.warn_about_v3_api('Zip::File.split')
|
||||
end
|
||||
|
||||
zip_file_size = ::File.size(zip_file_name)
|
||||
segment_size = get_segment_size_for_split(segment_size)
|
||||
segment_size = get_segment_size_for_split(segment_size || dep_segment_size)
|
||||
return if zip_file_size <= segment_size
|
||||
|
||||
segment_count = get_segment_count_for_split(zip_file_size, segment_size)
|
||||
# Checking for correct zip structure
|
||||
::Zip::File.open(zip_file_name) {}
|
||||
partial_zip_file_name = get_partial_zip_file_name(zip_file_name, partial_zip_file_name)
|
||||
partial_zip_file_name = get_partial_zip_file_name(zip_file_name, (partial_zip_file_name || dep_partial_zip_file_name))
|
||||
szip_file_index = 0
|
||||
::File.open(zip_file_name, 'rb') do |zip_file|
|
||||
until zip_file.eof?
|
||||
|
@ -247,6 +263,7 @@ module Zip
|
|||
save_splited_part(zip_file, partial_zip_file_name, zip_file_size, szip_file_index, segment_size, segment_count)
|
||||
end
|
||||
end
|
||||
delete_zip_file = delete_zip_file.nil? ? dep_delete_zip_file : delete_zip_file
|
||||
::File.delete(zip_file_name) if delete_zip_file
|
||||
szip_file_index
|
||||
end
|
||||
|
@ -264,26 +281,45 @@ module Zip
|
|||
# specified. If a block is passed the stream object is passed to the block and
|
||||
# the stream is automatically closed afterwards just as with ruby's builtin
|
||||
# File.open method.
|
||||
def get_output_stream(entry, permission_int = nil, comment = nil,
|
||||
extra = nil, compressed_size = nil, crc = nil,
|
||||
compression_method = nil, size = nil, time = nil,
|
||||
# rubocop:disable Metrics/ParameterLists, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
||||
def get_output_stream(entry,
|
||||
dep_permission_int = nil, dep_comment = nil,
|
||||
dep_extra = nil, dep_compressed_size = nil, dep_crc = nil,
|
||||
dep_compression_method = nil, dep_size = nil, dep_time = nil,
|
||||
permission_int: nil, comment: nil,
|
||||
extra: nil, compressed_size: nil, crc: nil,
|
||||
compression_method: nil, size: nil, time: nil,
|
||||
&a_proc)
|
||||
|
||||
unless dep_permission_int.nil? && dep_comment.nil? && dep_extra.nil? &&
|
||||
dep_compressed_size.nil? && dep_crc.nil? && dep_compression_method.nil? &&
|
||||
dep_size.nil? && dep_time.nil?
|
||||
Zip.warn_about_v3_api('Zip::File#get_output_stream')
|
||||
end
|
||||
|
||||
new_entry =
|
||||
if entry.kind_of?(Entry)
|
||||
entry
|
||||
else
|
||||
Entry.new(@name, entry.to_s, comment, extra, compressed_size, crc, compression_method, size, time)
|
||||
Entry.new(@name, entry.to_s,
|
||||
comment: (comment || dep_comment),
|
||||
extra: (extra || dep_extra),
|
||||
compressed_size: (compressed_size || dep_compressed_size),
|
||||
crc: (crc || dep_crc),
|
||||
compression_method: (compression_method || dep_compression_method),
|
||||
size: (size || dep_size),
|
||||
time: (time || dep_time))
|
||||
end
|
||||
if new_entry.directory?
|
||||
raise ArgumentError,
|
||||
"cannot open stream to directory entry - '#{new_entry}'"
|
||||
end
|
||||
new_entry.unix_perms = permission_int
|
||||
new_entry.unix_perms = (permission_int || dep_permission_int)
|
||||
zip_streamable_entry = StreamableStream.new(new_entry)
|
||||
@entry_set << zip_streamable_entry
|
||||
zip_streamable_entry.get_output_stream(&a_proc)
|
||||
end
|
||||
# rubocop:enable Metrics/ParameterLists, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
||||
|
||||
# Returns the name of the zip archive
|
||||
def to_s
|
||||
|
@ -336,11 +372,25 @@ module Zip
|
|||
|
||||
# Extracts entry to file dest_path.
|
||||
def extract(entry, dest_path, &block)
|
||||
Zip.warn_about_v3_api('Zip::File#extract')
|
||||
|
||||
block ||= proc { ::Zip.on_exists_proc }
|
||||
found_entry = get_entry(entry)
|
||||
found_entry.extract(dest_path, &block)
|
||||
end
|
||||
|
||||
# Extracts `entry` to a file at `entry_path`, with `destination_directory`
|
||||
# as the base location in the filesystem.
|
||||
#
|
||||
# NB: The caller is responsible for making sure `destination_directory` is
|
||||
# safe, if it is passed.
|
||||
def extract_v3(entry, entry_path = nil, destination_directory: '.', &block)
|
||||
block ||= proc { ::Zip.on_exists_proc }
|
||||
found_entry = get_entry(entry)
|
||||
entry_path ||= found_entry.name
|
||||
found_entry.extract_v3(entry_path, destination_directory: destination_directory, &block)
|
||||
end
|
||||
|
||||
# Commits changes that has been made since the previous commit to
|
||||
# the zip archive.
|
||||
def commit
|
||||
|
@ -361,7 +411,9 @@ module Zip
|
|||
end
|
||||
|
||||
# Write buffer write changes to buffer and return
|
||||
def write_buffer(io = ::StringIO.new(''))
|
||||
def write_buffer(io = ::StringIO.new)
|
||||
return io unless commit_required?
|
||||
|
||||
::Zip::OutputStream.write_buffer(io) do |zos|
|
||||
@entry_set.each { |e| e.write_to_zip_output_stream(zos) }
|
||||
zos.comment = comment
|
||||
|
|
|
@ -239,7 +239,7 @@ module Zip
|
|||
end
|
||||
|
||||
def open(filename, mode = 'r', permissions = 0o644, &block)
|
||||
mode.delete!('b') # ignore b option
|
||||
mode = mode.delete('b') # ignore b option
|
||||
case mode
|
||||
when 'r'
|
||||
@mapped_zip.get_input_stream(filename, &block)
|
||||
|
@ -619,7 +619,7 @@ module Zip
|
|||
end
|
||||
|
||||
def expand_path(path)
|
||||
expanded = path.start_with?('/') ? path : ::File.join(@pwd, path)
|
||||
expanded = path.start_with?('/') ? path.dup : ::File.join(@pwd, path)
|
||||
expanded.gsub!(/\/\.(\/|$)/, '')
|
||||
expanded.gsub!(/[^\/]+\/\.\.(\/|$)/, '')
|
||||
expanded.empty? ? '/' : expanded
|
||||
|
|
|
@ -3,11 +3,11 @@ module Zip
|
|||
def initialize(*args)
|
||||
super
|
||||
|
||||
@buffer = +''
|
||||
@buffer = ''.b
|
||||
@zlib_inflater = ::Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
||||
end
|
||||
|
||||
def read(length = nil, outbuf = '')
|
||||
def read(length = nil, outbuf = ''.b)
|
||||
return (length.nil? || length.zero? ? '' : nil) if eof
|
||||
|
||||
while length.nil? || (@buffer.bytesize < length)
|
||||
|
|
|
@ -49,11 +49,17 @@ module Zip
|
|||
#
|
||||
# @param context [String||IO||StringIO] file path or IO/StringIO object
|
||||
# @param offset [Integer] offset in the IO/StringIO
|
||||
def initialize(context, offset = 0, decrypter = nil)
|
||||
def initialize(context, dep_offset = 0, dep_decrypter = nil, offset: 0, decrypter: nil)
|
||||
super()
|
||||
|
||||
if !dep_offset.zero? || !dep_decrypter.nil?
|
||||
Zip.warn_about_v3_api('Zip::InputStream.new')
|
||||
end
|
||||
|
||||
offset = dep_offset if offset.zero?
|
||||
@archive_io = get_io(context, offset)
|
||||
@decompressor = ::Zip::NullDecompressor
|
||||
@decrypter = decrypter || ::Zip::NullDecrypter.new
|
||||
@decrypter = decrypter || dep_decrypter || ::Zip::NullDecrypter.new
|
||||
@current_entry = nil
|
||||
end
|
||||
|
||||
|
@ -89,8 +95,14 @@ module Zip
|
|||
# Same as #initialize but if a block is passed the opened
|
||||
# stream is passed to the block and closed when the block
|
||||
# returns.
|
||||
def open(filename_or_io, offset = 0, decrypter = nil)
|
||||
zio = new(filename_or_io, offset, decrypter)
|
||||
def open(filename_or_io, dep_offset = 0, dep_decrypter = nil, offset: 0, decrypter: nil)
|
||||
if !dep_offset.zero? || !dep_decrypter.nil?
|
||||
Zip.warn_about_v3_api('Zip::InputStream.new')
|
||||
end
|
||||
|
||||
offset = dep_offset if offset.zero?
|
||||
|
||||
zio = new(filename_or_io, offset: offset, decrypter: decrypter || dep_decrypter)
|
||||
return zio unless block_given?
|
||||
|
||||
begin
|
||||
|
@ -101,7 +113,8 @@ module Zip
|
|||
end
|
||||
|
||||
def open_buffer(filename_or_io, offset = 0)
|
||||
warn 'open_buffer is deprecated!!! Use open instead!'
|
||||
Zip.warn_about_v3_api('Zip::InputStream.open_buffer')
|
||||
|
||||
::Zip::InputStream.open(filename_or_io, offset)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,14 +6,14 @@ module Zip
|
|||
|
||||
class << self
|
||||
def copy_stream(ostream, istream)
|
||||
ostream.write(istream.read(CHUNK_SIZE, '')) until istream.eof?
|
||||
ostream.write(istream.read(CHUNK_SIZE, ''.b)) until istream.eof?
|
||||
end
|
||||
|
||||
def copy_stream_n(ostream, istream, nbytes)
|
||||
toread = nbytes
|
||||
while toread > 0 && !istream.eof?
|
||||
tr = toread > CHUNK_SIZE ? CHUNK_SIZE : toread
|
||||
ostream.write(istream.read(tr, ''))
|
||||
ostream.write(istream.read(tr, ''.b))
|
||||
toread -= tr
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,13 +11,13 @@ module Zip
|
|||
super
|
||||
@lineno = 0
|
||||
@pos = 0
|
||||
@output_buffer = ''
|
||||
@output_buffer = ''.b
|
||||
end
|
||||
|
||||
attr_accessor :lineno
|
||||
attr_reader :pos
|
||||
|
||||
def read(number_of_bytes = nil, buf = '')
|
||||
def read(number_of_bytes = nil, buf = ''.b)
|
||||
tbuf = if @output_buffer.bytesize > 0
|
||||
if number_of_bytes <= @output_buffer.bytesize
|
||||
@output_buffer.slice!(0, number_of_bytes)
|
||||
|
@ -26,7 +26,7 @@ module Zip
|
|||
rbuf = sysread(number_of_bytes, buf)
|
||||
out = @output_buffer
|
||||
out << rbuf if rbuf
|
||||
@output_buffer = ''
|
||||
@output_buffer = ''.b
|
||||
out
|
||||
end
|
||||
else
|
||||
|
@ -93,7 +93,7 @@ module Zip
|
|||
|
||||
def flush
|
||||
ret_val = @output_buffer
|
||||
@output_buffer = ''
|
||||
@output_buffer = ''.b
|
||||
ret_val
|
||||
end
|
||||
|
||||
|
|
|
@ -24,10 +24,13 @@ module Zip
|
|||
|
||||
# Opens the indicated zip file. If a file with that name already
|
||||
# exists it will be overwritten.
|
||||
def initialize(file_name, stream = false, encrypter = nil)
|
||||
def initialize(file_name, dep_stream = false, dep_encrypter = nil, stream: false, encrypter: nil)
|
||||
super()
|
||||
|
||||
Zip.warn_about_v3_api('Zip::OutputStream.new') if dep_stream || !dep_encrypter.nil?
|
||||
|
||||
@file_name = file_name
|
||||
@output_stream = if stream
|
||||
@output_stream = if stream || dep_stream
|
||||
iostream = @file_name.dup
|
||||
iostream.reopen(@file_name)
|
||||
iostream.rewind
|
||||
|
@ -37,7 +40,7 @@ module Zip
|
|||
end
|
||||
@entry_set = ::Zip::EntrySet.new
|
||||
@compressor = ::Zip::NullCompressor.instance
|
||||
@encrypter = encrypter || ::Zip::NullEncrypter.new
|
||||
@encrypter = encrypter || dep_encrypter || ::Zip::NullEncrypter.new
|
||||
@closed = false
|
||||
@current_entry = nil
|
||||
@comment = nil
|
||||
|
@ -47,19 +50,23 @@ module Zip
|
|||
# stream is passed to the block and closed when the block
|
||||
# returns.
|
||||
class << self
|
||||
def open(file_name, encrypter = nil)
|
||||
def open(file_name, dep_encrypter = nil, encrypter: nil)
|
||||
return new(file_name) unless block_given?
|
||||
|
||||
zos = new(file_name, false, encrypter)
|
||||
Zip.warn_about_v3_api('Zip::OutputStream.open') unless dep_encrypter.nil?
|
||||
|
||||
zos = new(file_name, stream: false, encrypter: (encrypter || dep_encrypter))
|
||||
yield zos
|
||||
ensure
|
||||
zos.close if zos
|
||||
end
|
||||
|
||||
# Same as #open but writes to a filestream instead
|
||||
def write_buffer(io = ::StringIO.new(''), encrypter = nil)
|
||||
def write_buffer(io = ::StringIO.new, dep_encrypter = nil, encrypter: nil)
|
||||
Zip.warn_about_v3_api('Zip::OutputStream.write_buffer') unless dep_encrypter.nil?
|
||||
|
||||
io.binmode if io.respond_to?(:binmode)
|
||||
zos = new(io, true, encrypter)
|
||||
zos = new(io, stream: true, encrypter: (encrypter || dep_encrypter))
|
||||
yield zos
|
||||
zos.close_buffer
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ module Zip
|
|||
@read_so_far = 0
|
||||
end
|
||||
|
||||
def read(length = nil, outbuf = '')
|
||||
def read(length = nil, outbuf = ''.b)
|
||||
return (length.nil? || length.zero? ? '' : nil) if eof
|
||||
|
||||
if length.nil? || (@read_so_far + length) > decompressed_size
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module Zip
|
||||
VERSION = '2.3.0'
|
||||
VERSION = '2.4.1'
|
||||
end
|
||||
|
|
|
@ -5,8 +5,10 @@ require 'zip/version'
|
|||
Gem::Specification.new do |s|
|
||||
s.name = 'rubyzip'
|
||||
s.version = ::Zip::VERSION
|
||||
s.authors = ['Alexander Simonov']
|
||||
s.email = ['alex@simonov.me']
|
||||
s.authors = ['Robert Haines', 'John Lees-Miller', 'Alexander Simonov']
|
||||
s.email = [
|
||||
'hainesr@gmail.com', 'jdleesmiller@gmail.com', 'alex@simonov.me'
|
||||
]
|
||||
s.homepage = 'http://github.com/rubyzip/rubyzip'
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.summary = 'rubyzip is a ruby module for reading and writing zip files'
|
||||
|
@ -14,16 +16,42 @@ Gem::Specification.new do |s|
|
|||
s.require_paths = ['lib']
|
||||
s.license = 'BSD 2-Clause'
|
||||
s.metadata = {
|
||||
'bug_tracker_uri' => 'https://github.com/rubyzip/rubyzip/issues',
|
||||
'changelog_uri' => "https://github.com/rubyzip/rubyzip/blob/v#{s.version}/Changelog.md",
|
||||
'documentation_uri' => "https://www.rubydoc.info/gems/rubyzip/#{s.version}",
|
||||
'source_code_uri' => "https://github.com/rubyzip/rubyzip/tree/v#{s.version}",
|
||||
'wiki_uri' => 'https://github.com/rubyzip/rubyzip/wiki'
|
||||
'bug_tracker_uri' => 'https://github.com/rubyzip/rubyzip/issues',
|
||||
'changelog_uri' => "https://github.com/rubyzip/rubyzip/blob/v#{s.version}/Changelog.md",
|
||||
'documentation_uri' => "https://www.rubydoc.info/gems/rubyzip/#{s.version}",
|
||||
'source_code_uri' => "https://github.com/rubyzip/rubyzip/tree/v#{s.version}",
|
||||
'wiki_uri' => 'https://github.com/rubyzip/rubyzip/wiki',
|
||||
'rubygems_mfa_required' => 'true'
|
||||
}
|
||||
s.required_ruby_version = '>= 2.4'
|
||||
s.add_development_dependency 'coveralls', '~> 0.7'
|
||||
s.add_development_dependency 'minitest', '~> 5.4'
|
||||
s.add_development_dependency 'pry', '~> 0.10'
|
||||
s.add_development_dependency 'rake', '~> 12.3', '>= 12.3.3'
|
||||
s.add_development_dependency 'rubocop', '~> 0.79'
|
||||
|
||||
s.post_install_message = <<~ENDBANNER
|
||||
RubyZip 3.0 is coming!
|
||||
**********************
|
||||
|
||||
The public API of some Rubyzip classes has been modernized to use named
|
||||
parameters for optional arguments. Please check your usage of the
|
||||
following classes:
|
||||
* `Zip::File`
|
||||
* `Zip::Entry`
|
||||
* `Zip::InputStream`
|
||||
* `Zip::OutputStream`
|
||||
* `Zip::DOSTime`
|
||||
|
||||
Run your test suite with the `RUBYZIP_V3_API_WARN` environment
|
||||
variable set to see warnings about usage of the old API. This will
|
||||
help you to identify any changes that you need to make to your code.
|
||||
See https://github.com/rubyzip/rubyzip/wiki/Updating-to-version-3.x for
|
||||
more information.
|
||||
|
||||
Please ensure that your Gemfiles and .gemspecs are suitably restrictive
|
||||
to avoid an unexpected breakage when 3.0 is released (e.g. ~> 2.3.0).
|
||||
See https://github.com/rubyzip/rubyzip for details. The Changelog also
|
||||
lists other enhancements and bugfixes that have been implemented since
|
||||
version 2.3.0.
|
||||
ENDBANNER
|
||||
end
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ConstantsTest < MiniTest::Test
|
||||
def test_version_number_format
|
||||
# Should at least start with MAJoR.MINOR.PATCH, but
|
||||
# allow for additional version information after that.
|
||||
assert_match(/\A\d+\.\d+\.\d+/, Zip::VERSION)
|
||||
end
|
||||
|
||||
def test_compression_methods
|
||||
assert_equal(0, Zip::COMPRESSION_METHOD_STORE)
|
||||
assert_equal(1, Zip::COMPRESSION_METHOD_SHRINK)
|
||||
|
|
|
@ -19,7 +19,7 @@ class EncryptionTest < MiniTest::Test
|
|||
@rand = [250, 143, 107, 13, 143, 22, 155, 75, 228, 150, 12]
|
||||
@output = ::Zip::DOSTime.stub(:now, ::Zip::DOSTime.new(2014, 12, 17, 15, 56, 24)) do
|
||||
Random.stub(:rand, ->(_range) { @rand.shift }) do
|
||||
Zip::OutputStream.write_buffer(::StringIO.new(''), Zip::TraditionalEncrypter.new('password')) do |zos|
|
||||
Zip::OutputStream.write_buffer(::StringIO.new, Zip::TraditionalEncrypter.new('password')) do |zos|
|
||||
zos.put_next_entry('file1.txt')
|
||||
zos.write ::File.open(INPUT_FILE1).read
|
||||
end.string
|
||||
|
|
|
@ -104,17 +104,27 @@ class ZipFileTest < MiniTest::Test
|
|||
end
|
||||
|
||||
def test_open_buffer_with_string
|
||||
string = File.read('test/data/rubycode.zip')
|
||||
data = File.read('test/data/rubycode.zip', mode: 'rb')
|
||||
string = data.dup
|
||||
|
||||
::Zip::File.open_buffer string do |zf|
|
||||
assert zf.entries.map(&:name).include?('zippedruby1.rb')
|
||||
end
|
||||
|
||||
# Ensure the buffer hasn't changed.
|
||||
assert_equal(data, string)
|
||||
end
|
||||
|
||||
def test_open_buffer_with_stringio
|
||||
string_io = StringIO.new File.read('test/data/rubycode.zip')
|
||||
data = File.read('test/data/rubycode.zip', mode: 'rb')
|
||||
string_io = StringIO.new(data.dup)
|
||||
|
||||
::Zip::File.open_buffer string_io do |zf|
|
||||
assert zf.entries.map(&:name).include?('zippedruby1.rb')
|
||||
end
|
||||
|
||||
# Ensure the buffer hasn't changed.
|
||||
assert_equal(data, string_io.string)
|
||||
end
|
||||
|
||||
def test_close_buffer_with_stringio
|
||||
|
@ -123,6 +133,18 @@ class ZipFileTest < MiniTest::Test
|
|||
assert_nil zf.close
|
||||
end
|
||||
|
||||
def test_open_buffer_without_block_write_buffer_does_nothing
|
||||
data = File.read('test/data/rubycode.zip', mode: 'rb')
|
||||
string_io = StringIO.new(data.dup)
|
||||
|
||||
zf = ::Zip::File.open_buffer(string_io)
|
||||
assert zf.entries.map(&:name).include?('zippedruby1.rb')
|
||||
|
||||
# Ensure the buffer isn't changed.
|
||||
assert_same string_io, zf.write_buffer(string_io)
|
||||
assert_equal(data, string_io.string)
|
||||
end
|
||||
|
||||
def test_open_buffer_no_op_does_not_change_file
|
||||
Dir.mktmpdir do |tmp|
|
||||
test_zip = File.join(tmp, 'test.zip')
|
||||
|
@ -481,7 +503,7 @@ class ZipFileTest < MiniTest::Test
|
|||
zf = ::Zip::File.new(TEST_ZIP.zip_name)
|
||||
old_name = zf.entries.first
|
||||
zf.rename(old_name, new_name)
|
||||
io = ::StringIO.new('')
|
||||
io = ::StringIO.new
|
||||
buffer = zf.write_buffer(io)
|
||||
File.open(TEST_ZIP.zip_name, 'wb') { |f| f.write buffer.string }
|
||||
zf_read = ::Zip::File.new(TEST_ZIP.zip_name)
|
||||
|
@ -630,7 +652,7 @@ class ZipFileTest < MiniTest::Test
|
|||
end
|
||||
|
||||
def test_streaming
|
||||
fname = ::File.join(::File.expand_path(::File.dirname(__FILE__)), '../README.md')
|
||||
fname = ::File.join(__dir__, '../README.md')
|
||||
zname = 'test/data/generated/README.zip'
|
||||
Zip::File.open(zname, Zip::File::CREATE) do |zipfile|
|
||||
zipfile.get_output_stream(File.basename(fname)) do |f|
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
require 'test_helper'
|
||||
|
||||
require 'forwardable'
|
||||
|
||||
class ZipInputStreamTest < MiniTest::Test
|
||||
include AssertEntry
|
||||
|
||||
|
@ -134,7 +136,7 @@ class ZipInputStreamTest < MiniTest::Test
|
|||
assert_equal(TestZipFile::TEST_ZIP2.entry_names[0], e.name)
|
||||
|
||||
# Do a little reading
|
||||
buf = ''
|
||||
buf = ''.b
|
||||
buf << zis.read(100)
|
||||
assert_equal(100, zis.pos)
|
||||
buf << (zis.gets || '')
|
||||
|
@ -143,7 +145,7 @@ class ZipInputStreamTest < MiniTest::Test
|
|||
|
||||
zis.rewind
|
||||
|
||||
buf2 = ''
|
||||
buf2 = ''.b
|
||||
buf2 << zis.read(100)
|
||||
buf2 << (zis.gets || '')
|
||||
buf2 << (zis.gets || '')
|
||||
|
|
|
@ -8,7 +8,7 @@ class AbstractOutputStreamTest < MiniTest::Test
|
|||
attr_accessor :buffer
|
||||
|
||||
def initialize
|
||||
@buffer = ''
|
||||
@buffer = ''.b
|
||||
end
|
||||
|
||||
def <<(data)
|
||||
|
@ -58,12 +58,12 @@ class AbstractOutputStreamTest < MiniTest::Test
|
|||
assert_equal("hello world. You ok out there?\nI sure hope so!\n", @output_stream.buffer)
|
||||
|
||||
$, = 'X'
|
||||
@output_stream.buffer = ''
|
||||
@output_stream.buffer = ''.b
|
||||
@output_stream.print('monkey', 'duck', 'zebra')
|
||||
assert_equal("monkeyXduckXzebra\n", @output_stream.buffer)
|
||||
|
||||
$\ = nil
|
||||
@output_stream.buffer = ''
|
||||
@output_stream.buffer = ''.b
|
||||
@output_stream.print(20)
|
||||
assert_equal('20', @output_stream.buffer)
|
||||
end
|
||||
|
@ -87,19 +87,19 @@ class AbstractOutputStreamTest < MiniTest::Test
|
|||
@output_stream.puts('hello', 'world')
|
||||
assert_equal("\nhello\nworld\n", @output_stream.buffer)
|
||||
|
||||
@output_stream.buffer = ''
|
||||
@output_stream.buffer = ''.b
|
||||
@output_stream.puts("hello\n", "world\n")
|
||||
assert_equal("hello\nworld\n", @output_stream.buffer)
|
||||
|
||||
@output_stream.buffer = ''
|
||||
@output_stream.buffer = ''.b
|
||||
@output_stream.puts(%W[hello\n world\n])
|
||||
assert_equal("hello\nworld\n", @output_stream.buffer)
|
||||
|
||||
@output_stream.buffer = ''
|
||||
@output_stream.buffer = ''.b
|
||||
@output_stream.puts(%W[hello\n world\n], 'bingo')
|
||||
assert_equal("hello\nworld\nbingo\n", @output_stream.buffer)
|
||||
|
||||
@output_stream.buffer = ''
|
||||
@output_stream.buffer = ''.b
|
||||
@output_stream.puts(16, 20, 50, 'hello')
|
||||
assert_equal("16\n20\n50\nhello\n", @output_stream.buffer)
|
||||
end
|
||||
|
|
|
@ -23,7 +23,7 @@ class ZipOutputStreamTest < MiniTest::Test
|
|||
end
|
||||
|
||||
def test_write_buffer
|
||||
io = ::StringIO.new('')
|
||||
io = ::StringIO.new
|
||||
buffer = ::Zip::OutputStream.write_buffer(io) do |zos|
|
||||
zos.comment = TEST_ZIP.comment
|
||||
write_test_zip(zos)
|
||||
|
@ -33,7 +33,7 @@ class ZipOutputStreamTest < MiniTest::Test
|
|||
end
|
||||
|
||||
def test_write_buffer_binmode
|
||||
io = ::StringIO.new('')
|
||||
io = ::StringIO.new
|
||||
buffer = ::Zip::OutputStream.write_buffer(io) do |zos|
|
||||
zos.comment = TEST_ZIP.comment
|
||||
write_test_zip(zos)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
require 'simplecov'
|
||||
require 'minitest/autorun'
|
||||
require 'minitest/unit'
|
||||
require 'fileutils'
|
||||
|
@ -146,7 +145,7 @@ module CrcTest
|
|||
attr_accessor :buffer
|
||||
|
||||
def initialize
|
||||
@buffer = ''
|
||||
@buffer = ''.b
|
||||
end
|
||||
|
||||
def <<(data)
|
||||
|
@ -223,3 +222,21 @@ module ZipEntryData
|
|||
TEST_ISDIRECTORY = false
|
||||
TEST_TIME = Time.now
|
||||
end
|
||||
|
||||
module ZipV3Assertions
|
||||
def assert_v3_api_warning
|
||||
env_save = ENV['RUBYZIP_V3_API_WARN']
|
||||
ENV['RUBYZIP_V3_API_WARN'] = '1'
|
||||
assert_output('', /^You have called/) { yield }
|
||||
ensure
|
||||
ENV['RUBYZIP_V3_API_WARN'] = env_save
|
||||
end
|
||||
|
||||
def refute_v3_api_warning
|
||||
env_save = ENV['RUBYZIP_V3_API_WARN']
|
||||
ENV['RUBYZIP_V3_API_WARN'] = '1'
|
||||
assert_output('', '') { yield }
|
||||
ensure
|
||||
ENV['RUBYZIP_V3_API_WARN'] = env_save
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,283 @@
|
|||
require 'test_helper'
|
||||
|
||||
module Version3APITest
|
||||
class ZipFileTest < MiniTest::Test
|
||||
include CommonZipFileFixture
|
||||
include ZipV3Assertions
|
||||
|
||||
def test_new
|
||||
assert_v3_api_warning do
|
||||
file = ::Zip::File.new(TEST_ZIP.zip_name, true, false, restore_times: true) {}
|
||||
assert(file.restore_times)
|
||||
refute(file.restore_permissions)
|
||||
end
|
||||
|
||||
assert_v3_api_warning do
|
||||
string_io = StringIO.new(File.read('test/data/rubycode.zip'))
|
||||
file = ::Zip::File.new(string_io, false, true, restore_times: true) {}
|
||||
assert(file.restore_times)
|
||||
refute(file.restore_permissions)
|
||||
end
|
||||
|
||||
refute_v3_api_warning do
|
||||
file = ::Zip::File.new(TEST_ZIP.zip_name, create: true, restore_times: true) {}
|
||||
assert(file.restore_times)
|
||||
refute(file.restore_permissions)
|
||||
end
|
||||
|
||||
refute_v3_api_warning do
|
||||
string_io = StringIO.new(File.read('test/data/rubycode.zip'))
|
||||
file = ::Zip::File.new(string_io, buffer: true, restore_times: true) {}
|
||||
assert(file.restore_times)
|
||||
refute(file.restore_permissions)
|
||||
end
|
||||
end
|
||||
|
||||
def test_open
|
||||
refute_v3_api_warning do
|
||||
file = ::Zip::File.open('test/data/rubycode.zip', restore_permissions: true)
|
||||
assert(file.restore_permissions)
|
||||
refute(file.restore_times)
|
||||
file.close
|
||||
end
|
||||
|
||||
assert_v3_api_warning do
|
||||
file = ::Zip::File.open(TEST_ZIP.zip_name, true, restore_permissions: true)
|
||||
assert(file.restore_permissions)
|
||||
refute(file.restore_times)
|
||||
file.close
|
||||
end
|
||||
|
||||
refute_v3_api_warning do
|
||||
file = ::Zip::File.open(TEST_ZIP.zip_name, create: true, restore_permissions: true)
|
||||
assert(file.restore_permissions)
|
||||
refute(file.restore_times)
|
||||
file.close
|
||||
end
|
||||
end
|
||||
|
||||
def test_add_buffer
|
||||
assert_v3_api_warning do
|
||||
Zip::File.add_buffer {}
|
||||
end
|
||||
end
|
||||
|
||||
def test_get_output_stream
|
||||
refute_v3_api_warning do
|
||||
zf = ::Zip::File.new(EMPTY_FILENAME, create: true)
|
||||
zf.get_output_stream('myFile') { |os| os.write 'myFile contains just this' }
|
||||
zf.close
|
||||
end
|
||||
|
||||
assert_v3_api_warning do
|
||||
zf = ::Zip::File.new(EMPTY_FILENAME, create: true)
|
||||
zf.get_output_stream('myFile', 0o644) { |os| os.write 'myFile contains just this' }
|
||||
zf.close
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ZipEntryTest < MiniTest::Test
|
||||
include ZipEntryData
|
||||
include ZipV3Assertions
|
||||
|
||||
def test_v3_constructor_and_getters
|
||||
refute_v3_api_warning do
|
||||
entry = ::Zip::Entry.new(TEST_ZIPFILE,
|
||||
TEST_NAME,
|
||||
comment: TEST_COMMENT,
|
||||
extra: TEST_EXTRA,
|
||||
compressed_size: TEST_COMPRESSED_SIZE,
|
||||
crc: TEST_CRC,
|
||||
compression_method: TEST_COMPRESSIONMETHOD,
|
||||
size: TEST_SIZE,
|
||||
time: TEST_TIME)
|
||||
|
||||
assert_equal(TEST_COMMENT, entry.comment)
|
||||
assert_equal(TEST_COMPRESSED_SIZE, entry.compressed_size)
|
||||
assert_equal(TEST_CRC, entry.crc)
|
||||
assert_instance_of(::Zip::ExtraField, entry.extra)
|
||||
assert_equal(TEST_COMPRESSIONMETHOD, entry.compression_method)
|
||||
assert_equal(TEST_NAME, entry.name)
|
||||
assert_equal(TEST_SIZE, entry.size)
|
||||
assert_equal(TEST_TIME, entry.time)
|
||||
end
|
||||
end
|
||||
|
||||
def test_basic_constructor
|
||||
refute_v3_api_warning do
|
||||
::Zip::Entry.new(TEST_ZIPFILE, TEST_NAME)
|
||||
end
|
||||
end
|
||||
|
||||
def test_v2_constructor_and_getters
|
||||
assert_v3_api_warning do
|
||||
entry = ::Zip::Entry.new(TEST_ZIPFILE,
|
||||
TEST_NAME,
|
||||
TEST_COMMENT,
|
||||
TEST_EXTRA,
|
||||
TEST_COMPRESSED_SIZE,
|
||||
TEST_CRC,
|
||||
TEST_COMPRESSIONMETHOD,
|
||||
TEST_SIZE,
|
||||
TEST_TIME)
|
||||
|
||||
assert_equal(TEST_COMMENT, entry.comment)
|
||||
assert_equal(TEST_COMPRESSED_SIZE, entry.compressed_size)
|
||||
assert_equal(TEST_CRC, entry.crc)
|
||||
assert_instance_of(::Zip::ExtraField, entry.extra)
|
||||
assert_equal(TEST_COMPRESSIONMETHOD, entry.compression_method)
|
||||
assert_equal(TEST_NAME, entry.name)
|
||||
assert_equal(TEST_SIZE, entry.size)
|
||||
assert_equal(TEST_TIME, entry.time)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ZipInputStreamTest < MiniTest::Test
|
||||
include ZipV3Assertions
|
||||
|
||||
def test_new_with_old_offset
|
||||
assert_v3_api_warning do
|
||||
zis = ::Zip::InputStream.new(TestZipFile::TEST_ZIP2.zip_name, 100)
|
||||
assert_equal(100, zis.instance_variable_get(:@archive_io).pos)
|
||||
zis.close
|
||||
end
|
||||
end
|
||||
|
||||
def test_new_with_new_offset
|
||||
refute_v3_api_warning do
|
||||
zis = ::Zip::InputStream.new(TestZipFile::TEST_ZIP2.zip_name, offset: 100)
|
||||
assert_equal(100, zis.instance_variable_get(:@archive_io).pos)
|
||||
zis.close
|
||||
end
|
||||
end
|
||||
|
||||
def test_new_with_clashing_offset
|
||||
assert_v3_api_warning do
|
||||
zis = ::Zip::InputStream.new(TestZipFile::TEST_ZIP2.zip_name, 10, offset: 100)
|
||||
assert_equal(100, zis.instance_variable_get(:@archive_io).pos)
|
||||
zis.close
|
||||
end
|
||||
end
|
||||
|
||||
def test_open
|
||||
refute_v3_api_warning do
|
||||
::Zip::InputStream.open(TestZipFile::TEST_ZIP2.zip_name) {}
|
||||
end
|
||||
|
||||
refute_v3_api_warning do
|
||||
::Zip::InputStream.open(TestZipFile::TEST_ZIP2.zip_name, decrypter: true) {}
|
||||
end
|
||||
|
||||
assert_v3_api_warning do
|
||||
::Zip::InputStream.open(TestZipFile::TEST_ZIP2.zip_name, 100, nil) {}
|
||||
end
|
||||
end
|
||||
|
||||
def test_open_buffer
|
||||
assert_v3_api_warning do
|
||||
::Zip::InputStream.open_buffer(StringIO.new)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ZipOutputStreamTest < MiniTest::Test
|
||||
include ZipV3Assertions
|
||||
|
||||
TEST_ZIP = TestZipFile::TEST_ZIP2.clone
|
||||
TEST_ZIP.zip_name = 'test/data/generated/output.zip'
|
||||
|
||||
def test_new
|
||||
refute_v3_api_warning do
|
||||
::Zip::OutputStream.new(TEST_ZIP.zip_name)
|
||||
end
|
||||
|
||||
refute_v3_api_warning do
|
||||
::Zip::OutputStream.new(StringIO.new, stream: true)
|
||||
end
|
||||
|
||||
assert_v3_api_warning do
|
||||
::Zip::OutputStream.new(StringIO.new, true)
|
||||
end
|
||||
|
||||
refute_v3_api_warning do
|
||||
::Zip::OutputStream.new(TEST_ZIP.zip_name, stream: false, encrypter: true)
|
||||
end
|
||||
|
||||
assert_v3_api_warning do
|
||||
::Zip::OutputStream.new(TEST_ZIP.zip_name, false, true)
|
||||
end
|
||||
end
|
||||
|
||||
def test_open
|
||||
refute_v3_api_warning do
|
||||
::Zip::OutputStream.open(TEST_ZIP.zip_name) {}
|
||||
end
|
||||
|
||||
refute_v3_api_warning do
|
||||
::Zip::OutputStream.open(TEST_ZIP.zip_name, encrypter: true) {}
|
||||
end
|
||||
|
||||
assert_v3_api_warning do
|
||||
::Zip::OutputStream.open(TEST_ZIP.zip_name, true) {}
|
||||
end
|
||||
end
|
||||
|
||||
def test_write_buffer
|
||||
refute_v3_api_warning do
|
||||
::Zip::OutputStream.write_buffer(StringIO.new) {}
|
||||
end
|
||||
|
||||
refute_v3_api_warning do
|
||||
::Zip::OutputStream.write_buffer(StringIO.new, encrypter: true) {}
|
||||
end
|
||||
|
||||
assert_v3_api_warning do
|
||||
::Zip::OutputStream.write_buffer(StringIO.new, true) {}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ZipFileSplitTest < MiniTest::Test
|
||||
include ZipV3Assertions
|
||||
|
||||
TEST_ZIP = TestZipFile::TEST_ZIP2.clone
|
||||
TEST_ZIP.zip_name = 'large_zip_file.zip'
|
||||
|
||||
def setup
|
||||
FileUtils.cp(TestZipFile::TEST_ZIP2.zip_name, TEST_ZIP.zip_name)
|
||||
end
|
||||
|
||||
def teardown
|
||||
File.delete(TEST_ZIP.zip_name)
|
||||
|
||||
Dir["#{TEST_ZIP.zip_name}.*"].each do |zip_file_name|
|
||||
File.delete(zip_file_name) if File.exist?(zip_file_name)
|
||||
end
|
||||
end
|
||||
|
||||
def test_old_split
|
||||
assert_v3_api_warning do
|
||||
Zip::File.split(TEST_ZIP.zip_name, 65_536, false)
|
||||
end
|
||||
end
|
||||
|
||||
def test_new_split
|
||||
refute_v3_api_warning do
|
||||
Zip::File.split(TEST_ZIP.zip_name, segment_size: 65_536, delete_zip_file: false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ZipDOSTimeTest < MiniTest::Test
|
||||
include ZipV3Assertions
|
||||
|
||||
def test_dos_equals
|
||||
assert_v3_api_warning do
|
||||
time = ::Zip::DOSTime.now
|
||||
assert(time.dos_equals(time))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue