omnizip 0.4.5 → 0.4.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5a55c37209e986f7e4499e8a485163728e9c8f0dff506e1aa852672a9585653f
4
- data.tar.gz: ba0b5437026feed4c1fe4d0ab0146f868386ebe2284ec7b08b45c7260930d582
3
+ metadata.gz: f958a6bde5f52729231c66fcc680ecaf30bd3bb3e3a04f59bd843a63f5d664ec
4
+ data.tar.gz: c35f940965b7776bbab14f41258917bf4ae444899ec70d4c0713a36a12d5c05b
5
5
  SHA512:
6
- metadata.gz: 13d25032be26ccd096718846ac74126fd14ab3e2729d1e9ed366a3c431815b69c0817e33092f214eea4ed041e41e2eebe070ac92862bd54c70b0379017281637
7
- data.tar.gz: 8e68e9a4a0d7f489be9956baf6f2d18bb82d5cc0db123adaf689ab73aefca1dcb44c0172a8e774c0cbcfbcca2927c9f40b62da184678588e084642b3b86cd7eb
6
+ metadata.gz: 6e219d9d7052b667c112709d0ebaa4a4e3b6925e374694f1fd646114e6ab7d2157e255a07a8e05b9a42a9234b4e61841617ce4682b6e79727ee6a4381a4e2b35
7
+ data.tar.gz: f6921e7de8606e19dd28e62d4a00a8bec55b2f0bc6f4a4478805df6299f88b912aa6b8ea56fbf774f6df42a7f29cc707d709c4dc250c702a5d3b4ca91d785601
data/CHANGELOG.md CHANGED
@@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Added
11
+ - Prebuilt-binary distribution (parsanol model): platform gems
12
+ (x86_64/aarch64/arm Linux glibc+musl, arm64/x86_64 macOS,
13
+ x64/aarch64-mingw-ucrt, x64-mingw32) now vendor the prebuilt
14
+ `omnizip-ffi` cdylib — `gem install omnizip` gives Rust
15
+ acceleration with zero compilation on those platforms. The plain
16
+ `ruby` gem and every platform without a binary (JRuby,
17
+ TruffleRuby, anything else) stay fully functional on the pure-Ruby
18
+ core. The cdylibs are cross-built by omnizip-rs's release-binary
19
+ workflow and attached to each `omnizip-ffi-v*` release;
20
+ `rake platform_gems:build` packages them and `gem-build.yml`
21
+ smoke-tests each installed gem (tier active + pure-Ruby path with
22
+ `OMNIZIP_NO_RUST=1`).
23
+ - `OMNIZIP_NO_RUST=1` kill switch forces the pure-Ruby core
24
+ everywhere; `Library.resolve_path` (public now) prefers the
25
+ vendored cdylib over dev checkouts; `Library.dylib_version`
26
+ reports the Rust release a loaded cdylib was built from
27
+ (`ozip_version`, new in omnizip-rs 0.21.109).
28
+
10
29
  ### Fixed
11
30
  - PPMd works for the first time: the pure-Ruby ppmd7 core cannot
12
31
  decode its own output (root-only decoder, 100-symbol cap — proven)
@@ -25,6 +44,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
25
44
  route decode through the Rust backend when it loads, each pinned by
26
45
  a cross-implementation differential. A Rust failure falls back to
27
46
  the Ruby core — auto mode is never worse than pure Ruby.
47
+ - Archive-level acceleration: `Implementations::Rust::Archive` binds
48
+ the cdylib's whole-archive surface (open, list entries, read entry)
49
+ over every multi-entry format — zip, tar, cpio, 7z, rar3/4/5, iso,
50
+ rpm, xar, ole, encrypted archives included. `ZipHandler#list` and
51
+ `#read_entry` route through it first (auto mode; any Rust error or
52
+ a missing cdylib falls back to the pure-Ruby path). The tier's
53
+ 600-mutant fuzz gate also caught a Rust decompression bomb
54
+ (truncated deflate streams decoded an endless phantom bit-stream;
55
+ fixed upstream in omnizip 0.21.108).
56
+ - `Library#bind` / `Library#take_buffer` seams the archive surface
57
+ rides (Fiddle symbol binding + copy-out-and-free).
28
58
 
29
59
  ### Fixed
30
60
  - RAR recovery-record repair fails loudly instead of pretending:
data/README.adoc CHANGED
@@ -28,6 +28,28 @@ It provides both a command-line interface and a programmatic Ruby API, making it
28
28
 
29
29
  See link:readme-docs/compression-algorithms.adoc[Compression Algorithms Guide] for detailed information.
30
30
 
31
+ ==== Rust Acceleration (prebuilt, zero compilation)
32
+
33
+ Where the platform gem exists, `gem install omnizip` ships a prebuilt
34
+ `omnizip-ffi` cdylib and the codec + archive tiers route through it
35
+ automatically — no Rust toolchain, no compilation:
36
+
37
+ * x86_64-linux, aarch64-linux, arm-linux (glibc and musl)
38
+ * arm64-darwin, x86_64-darwin
39
+ * x64-mingw-ucrt, aarch64-mingw-ucrt, x64-mingw32
40
+
41
+ Everywhere else — including JRuby/TruffleRuby and any platform without
42
+ a binary — the gem stays fully functional on its pure-Ruby core (the
43
+ acceleration is strictly optional). Three escape hatches:
44
+
45
+ * `OMNIZIP_NO_RUST=1` — force the pure-Ruby core everywhere.
46
+ * `OMNIZIP_FFI_DYLIB=/path/to/libomnizip_ffi` — load a specific build.
47
+ * `rake rust:build` — build and vendor the cdylib yourself from a
48
+ checkout (developers).
49
+
50
+ Any Rust-side failure also falls back to the Ruby core mid-operation,
51
+ so `auto` mode is never worse than pure Ruby.
52
+
31
53
  ==== SDK-Compatible LZMA Mode (v0.2.0)
32
54
 
33
55
  Omnizip now provides SDK-compatible LZMA encoding and decoding for full XZ/LZMA tool compatibility.
@@ -48,6 +48,14 @@ module Omnizip
48
48
  end
49
49
 
50
50
  def list(path, details: false, **_)
51
+ # Whole-archive tier (names-only path): the Rust archive
52
+ # surface lists any supported format; the Ruby reader stays
53
+ # the fallback and the details path's source.
54
+ unless details
55
+ tier_names = Omnizip::Backends.archive_entry_names(path)
56
+ return tier_names if tier_names
57
+ end
58
+
51
59
  reader = Formats::Zip::Reader.new(path)
52
60
  return reader.entries.map(&:filename) unless details
53
61
 
@@ -65,6 +73,9 @@ module Omnizip
65
73
  end
66
74
 
67
75
  def read_entry(path, entry_name)
76
+ tier = Omnizip::Backends.archive_read_entry(path, entry_name)
77
+ return tier unless tier.nil?
78
+
68
79
  Formats::Zip::Reader.new(path).read_entry(entry_name)
69
80
  end
70
81
 
@@ -94,6 +94,26 @@ module Omnizip
94
94
  end
95
95
  end
96
96
 
97
+ # Whole-archive tier helpers: nil means "Rust unavailable or
98
+ # entry not found — caller falls back to the Ruby reader".
99
+ def archive_entry_names(path)
100
+ Omnizip::Implementations::Rust::Archive.open(File.binread(path)) { |a| return a.entry_names }
101
+ rescue Omnizip::Implementations::Rust::Archive::LibraryMissing, Omnizip::Implementations::Rust::Error, StandardError
102
+ nil
103
+ end
104
+
105
+ # rubocop:disable-next Lint/ReturnInVoidContext
106
+ def archive_read_entry(path, entry_name)
107
+ Omnizip::Implementations::Rust::Archive.open(File.binread(path)) do |a|
108
+ idx = a.entry_names.index(entry_name)
109
+ return nil if idx.nil?
110
+
111
+ return a.read_entry(idx)
112
+ end
113
+ rescue Omnizip::Implementations::Rust::Archive::LibraryMissing, Omnizip::Implementations::Rust::Error, StandardError
114
+ nil
115
+ end
116
+
97
117
  private
98
118
 
99
119
  def backend_rust
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omnizip
4
+ module Implementations
5
+ module Rust
6
+ # Whole-archive acceleration over the cdylib: open any supported
7
+ # format (auto-detected), list entries, read entry bytes. This is
8
+ # the archive-level tier surface — the Ruby core remains the
9
+ # fallback (the cdylib unavailable ⇒ these raise LibraryMissing
10
+ # and callers fall back).
11
+ class Archive
12
+ class LibraryMissing < StandardError; end
13
+
14
+ # Built lazily inside #initialize: the Fiddle::TYPE_* constants
15
+ # only resolve after a successful require, and Ruby 4.0 moved
16
+ # fiddle out of the default gems (same reason
17
+ # Library.function_table is a method, not a constant).
18
+ def initialize(data, password: nil)
19
+ lib = Library.instance
20
+ raise LibraryMissing, "omnizip-ffi cdylib not loaded" unless lib
21
+
22
+ @lib = lib
23
+ funcs = function_table
24
+ @funcs = funcs.each_with_object({}) do |(key, (name, args, ret)), h|
25
+ h[key] = lib.bind(name, args, ret)
26
+ end
27
+
28
+ pw = password&.to_s
29
+ pw_ptr = pw && !pw.empty? ? Fiddle::Pointer[pw] : nil
30
+ @handle = @funcs[:arch_open].call(Fiddle::Pointer[data], data.bytesize, pw_ptr)
31
+ return unless @handle.null?
32
+
33
+ raise Error, @lib.last_error
34
+ end
35
+
36
+ def entry_count
37
+ @funcs[:arch_count].call(@handle)
38
+ end
39
+
40
+ def entry_names
41
+ (0...entry_count).map do |i|
42
+ ptr = @funcs[:arch_entry_name].call(@handle, i)
43
+ next nil if ptr.null?
44
+
45
+ ptr.to_s
46
+ end
47
+ end
48
+
49
+ def entry_size(index)
50
+ @funcs[:arch_entry_size].call(@handle, index)
51
+ end
52
+
53
+ # Read one entry's uncompressed bytes.
54
+ #
55
+ # @return [String] binary
56
+ def read_entry(index)
57
+ out_len = [0].pack("Q")
58
+ ptr = @funcs[:arch_read_entry].call(@handle, index, out_len)
59
+ raise Error, @lib.last_error if ptr.null?
60
+
61
+ @lib.take_buffer(ptr, out_len.unpack1("Q"))
62
+ end
63
+
64
+ def close
65
+ return unless @handle
66
+
67
+ @funcs[:arch_close].call(@handle)
68
+ @handle = nil
69
+ end
70
+
71
+ def self.open(data, password: nil)
72
+ archive = new(data, password: password)
73
+ yield archive
74
+ ensure
75
+ archive&.close
76
+ end
77
+
78
+ private
79
+
80
+ def function_table
81
+ {
82
+ arch_open: ["ozip_arch_open", %i[voidp size_t voidp], Fiddle::TYPE_VOIDP],
83
+ arch_count: ["ozip_arch_count", [:voidp], Fiddle::TYPE_SIZE_T],
84
+ arch_entry_name: ["ozip_arch_entry_name", %i[voidp size_t], Fiddle::TYPE_VOIDP],
85
+ arch_entry_size: ["ozip_arch_entry_size", %i[voidp size_t], Fiddle::TYPE_VOIDP],
86
+ arch_read_entry: ["ozip_arch_read_entry", %i[voidp size_t voidp], Fiddle::TYPE_VOIDP],
87
+ arch_close: ["ozip_arch_close", [:voidp], Fiddle::TYPE_VOID],
88
+ }
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -76,30 +76,47 @@ module Omnizip
76
76
  }
77
77
  end
78
78
 
79
- private
80
-
81
- def open
82
- path = resolve_path
83
- return nil if path.nil?
84
-
85
- handle = Fiddle.dlopen(path.to_s)
86
- funcs = function_table.each_with_object({}) do |(key, (name, args, ret)), h|
87
- h[key] = Fiddle::Function.new(handle[name], args, ret)
88
- end
89
- new(funcs)
90
- rescue StandardError => e # includes Fiddle::DLError
91
- warn "omnizip: rust backend unavailable (#{e.message}); using pure Ruby" if ENV["OMNIZIP_BACKEND"] == "rust"
79
+ # The Rust release the loaded cdylib was built from (e.g.
80
+ # "0.21.108"), read through the ozip_version symbol — the
81
+ # platform-gem smoke gate asserts it matches. nil when the
82
+ # library is absent or predates the symbol.
83
+ def dylib_version
84
+ handle = instance&.instance_handle
85
+ return nil if handle.nil?
86
+
87
+ func = Fiddle::Function.new(handle["ozip_version"], [], Fiddle::TYPE_VOIDP)
88
+ ptr = func.call
89
+ ptr.null? ? nil : ptr.to_s
90
+ rescue StandardError
92
91
  nil
93
92
  end
94
93
 
95
- def resolve_path
94
+ # Resolve the cdylib path. Precedence:
95
+ #
96
+ # 1. OMNIZIP_NO_RUST=1 — hard kill switch (always nil, so
97
+ # the pure-Ruby core handles everything; also the smoke
98
+ # gate for "works without Rust").
99
+ # 2. OMNIZIP_FFI_DYLIB — explicit path (developer override).
100
+ # 3. vendor/ — the prebuilt cdylib. Platform gems ship it
101
+ # here and `rake rust:build` writes here; rubygems
102
+ # already matched the platform at install time, so no
103
+ # runtime architecture probing is needed and the wrong
104
+ # arch cannot be picked.
105
+ # 4. ext/ (legacy location).
106
+ # 5. A sibling omnizip-rs checkout.
107
+ #
108
+ # `dirs` overrides 3-5 (spec seam: staged candidate paths).
109
+ def resolve_path(dirs = nil)
110
+ return nil if ENV.fetch("OMNIZIP_NO_RUST", nil) == "1"
111
+
96
112
  explicit = ENV.fetch("OMNIZIP_FFI_DYLIB", nil)
97
113
  return Pathname.new(explicit) if explicit && File.file?(explicit)
98
114
 
99
- candidates = [
115
+ candidates = dirs || [
116
+ Pathname.new(__dir__).join("../../../../vendor"),
100
117
  Pathname.new(__dir__).join("../../../../ext/libomnizip_ffi"),
101
- sibling_checkout,
102
- ].compact.flatten
118
+ *sibling_checkout,
119
+ ]
103
120
 
104
121
  %w[.dylib .so .dll].each do |ext|
105
122
  candidates.each do |dir|
@@ -110,6 +127,22 @@ module Omnizip
110
127
  nil
111
128
  end
112
129
 
130
+ private
131
+
132
+ def open
133
+ path = resolve_path
134
+ return nil if path.nil?
135
+
136
+ handle = Fiddle.dlopen(path.to_s)
137
+ funcs = function_table.each_with_object({}) do |(key, (name, args, ret)), h|
138
+ h[key] = Fiddle::Function.new(handle[name], args, ret)
139
+ end
140
+ new(funcs, handle)
141
+ rescue StandardError => e # includes Fiddle::DLError
142
+ warn "omnizip: rust backend unavailable (#{e.message}); using pure Ruby" if ENV["OMNIZIP_BACKEND"] == "rust"
143
+ nil
144
+ end
145
+
113
146
  # A sibling omnizip-rs checkout: ../omnizip-rs relative to
114
147
  # this gem's repository root.
115
148
  def sibling_checkout
@@ -120,8 +153,9 @@ module Omnizip
120
153
  end
121
154
  end
122
155
 
123
- def initialize(functions)
156
+ def initialize(functions, handle = nil)
124
157
  @functions = functions.freeze
158
+ @handle = handle
125
159
  end
126
160
 
127
161
  def compress(codec, data, level)
@@ -136,11 +170,31 @@ module Omnizip
136
170
  take(ptr, out_len.unpack1("Q"))
137
171
  end
138
172
 
173
+ # Bind one extra C symbol from the loaded cdylib (the archive
174
+ # surface uses this; Fiddle::Function is immutable once built).
175
+ def bind(symbol, args, ret)
176
+ handle = instance_handle
177
+ raise Error, "cdylib not loaded" if handle.nil?
178
+
179
+ Fiddle::Function.new(handle[symbol.to_s], args, ret)
180
+ end
181
+
139
182
  def last_error
140
183
  ptr = @functions[:last_error].call
141
184
  ptr.null? ? "unknown error" : ptr.to_s
142
185
  end
143
186
 
187
+ # The raw Fiddle::Handle (for extra symbol binds).
188
+ def instance_handle
189
+ @handle
190
+ end
191
+
192
+ # Copy out + free one returned buffer (public seam for the
193
+ # archive surface).
194
+ def take_buffer(ptr, len)
195
+ take(ptr, len)
196
+ end
197
+
144
198
  private
145
199
 
146
200
  def call(name, codec, input, input_len, a, out_len)
@@ -20,6 +20,7 @@ module Omnizip
20
20
  # fallback on any Rust error.
21
21
  module Rust
22
22
  autoload :Library, "omnizip/implementations/rust/library"
23
+ autoload :Archive, "omnizip/implementations/rust/archive"
23
24
  end
24
25
  end
25
26
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Omnizip
4
- VERSION = "0.4.5"
4
+ VERSION = "0.4.7"
5
5
  end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Build per-platform gems that vendor a prebuilt omnizip-ffi cdylib,
4
+ # so `gem install omnizip` gives Rust acceleration with zero
5
+ # compilation (parsanol distribution model, adopted 2026-09-21).
6
+ #
7
+ # # after downloading the release-binary artifacts:
8
+ # gh release download omnizip-ffi-v0.21.108 -R omnizip/omnizip-rs \
9
+ # -p 'libomnizip_ffi-*.tar.gz' -D artifacts
10
+ # bundle exec rake platform_gems:build DIR=artifacts
11
+ #
12
+ # Each target tarball maps to one rubygems platform; the built gems
13
+ # land in pkg/. The plain `ruby` platform gem keeps shipping without
14
+ # a binary (pure-Ruby core; OMNIZIP_NO_RUST=1 disables the tier).
15
+
16
+ # rust target → rubygems platform (keep in sync with
17
+ # omnizip-rs .github/workflows/release-binary.yml)
18
+ PLATFORM_GEM_TARGETS = {
19
+ "x86_64-unknown-linux-gnu" => "x86_64-linux",
20
+ "aarch64-unknown-linux-gnu" => "aarch64-linux",
21
+ "arm-unknown-linux-gnueabihf" => "arm-linux",
22
+ "x86_64-unknown-linux-musl" => "x86_64-linux-musl",
23
+ "aarch64-unknown-linux-musl" => "aarch64-linux-musl",
24
+ "arm-unknown-linux-musleabihf" => "arm-linux-musl",
25
+ "aarch64-apple-darwin" => "arm64-darwin",
26
+ "x86_64-apple-darwin" => "x86_64-darwin",
27
+ "x86_64-pc-windows-msvc" => "x64-mingw-ucrt",
28
+ "aarch64-pc-windows-msvc" => "aarch64-mingw-ucrt",
29
+ "x86_64-pc-windows-gnu" => "x64-mingw32",
30
+ }.freeze
31
+
32
+ namespace :platform_gems do
33
+ desc "Build one platform gem: TARGET=<rust target> DYLIB=<cdylib path>"
34
+ task :one do
35
+ target = ENV.fetch("TARGET") { abort "TARGET=<rust target> required" }
36
+ dylib = ENV.fetch("DYLIB") { abort "DYLIB=<cdylib path> required" }
37
+ platform = PLATFORM_GEM_TARGETS[target] or abort "unknown target #{target} (see lib/tasks/platform_gems.rake)"
38
+ out = build_platform_gem(platform, dylib)
39
+ puts "built: #{out}"
40
+ end
41
+
42
+ desc "Build platform gems for every tarball in DIR=libomnizip_ffi-<target>.tar.gz"
43
+ task :build do
44
+ dir = ENV.fetch("DIR") { abort "DIR=<artifacts dir> required" }
45
+ Dir.glob(File.join(dir, "libomnizip_ffi-*.tar.gz")).each do |tarball|
46
+ target = File.basename(tarball, ".tar.gz").delete_prefix("libomnizip_ffi-")
47
+ platform = PLATFORM_GEM_TARGETS[target] or abort "no rubygems platform mapping for #{target}"
48
+ require "tmpdir"
49
+ Dir.mktmpdir do |tmp|
50
+ binary = extract_binary(tarball, tmp)
51
+ out = build_platform_gem(platform, binary)
52
+ puts "built: #{out} (#{File.size(out)} bytes)"
53
+ end
54
+ end
55
+ end
56
+
57
+ def extract_binary(tarball, tmp)
58
+ system("tar", "-xzf", tarball, "-C", tmp) or abort "tar failed for #{tarball}"
59
+ Dir.glob(File.join(tmp, "*")).first or abort "empty tarball #{tarball}"
60
+ end
61
+
62
+ # Stage the tracked gem files plus the vendored cdylib, flip the
63
+ # gemspec platform, and build.
64
+ def build_platform_gem(platform, dylib)
65
+ require "fileutils"
66
+ require "rubygems/package"
67
+ require "tmpdir"
68
+
69
+ gem_root = File.expand_path("../..", __dir__)
70
+ spec = Gem::Specification.load(File.join(gem_root, "omnizip.gemspec"))
71
+ abort "omnizip.gemspec failed to load" unless spec
72
+
73
+ Dir.mktmpdir do |tmp|
74
+ stage = File.join(tmp, "stage")
75
+ spec.files.each do |rel|
76
+ src = File.join(gem_root, rel)
77
+ next unless File.file?(src)
78
+
79
+ dst = File.join(stage, rel)
80
+ FileUtils.mkdir_p(File.dirname(dst))
81
+ FileUtils.cp(src, dst)
82
+ end
83
+
84
+ vendored = "vendor/libomnizip_ffi#{File.extname(dylib)}"
85
+ FileUtils.mkdir_p(File.join(stage, "vendor"))
86
+ FileUtils.cp(dylib, File.join(stage, vendored))
87
+
88
+ spec.platform = Gem::Platform.new(platform)
89
+ spec.files += [vendored]
90
+ spec.test_files = []
91
+
92
+ gemspec_path = File.join(stage, "omnizip.gemspec")
93
+ File.write(gemspec_path, spec.to_ruby)
94
+
95
+ pkg = File.join(tmp, "pkg")
96
+ FileUtils.mkdir_p(pkg)
97
+ Dir.chdir(stage) do
98
+ Gem::Package.build(spec)
99
+ end
100
+ built = Dir.glob(File.join(stage, "omnizip-*.gem")).first or
101
+ abort "gem build produced nothing for #{platform}"
102
+ FileUtils.mkdir_p(File.join(gem_root, "pkg"))
103
+ FileUtils.mv(built, File.join(gem_root, "pkg", File.basename(built)))
104
+ File.join(gem_root, "pkg", File.basename(built))
105
+ end
106
+ end
107
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omnizip
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.5
4
+ version: 0.4.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-09-20 00:00:00.000000000 Z
11
+ date: 2026-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64
@@ -601,6 +601,7 @@ files:
601
601
  - lib/omnizip/implementations/base/lzma_encoder_base.rb
602
602
  - lib/omnizip/implementations/base/state_machine_base.rb
603
603
  - lib/omnizip/implementations/rust.rb
604
+ - lib/omnizip/implementations/rust/archive.rb
604
605
  - lib/omnizip/implementations/rust/library.rb
605
606
  - lib/omnizip/implementations/seven_zip.rb
606
607
  - lib/omnizip/implementations/seven_zip/lzma.rb
@@ -723,6 +724,7 @@ files:
723
724
  - lib/omnizip/zip/input_stream.rb
724
725
  - lib/omnizip/zip/output_stream.rb
725
726
  - lib/tasks/msi_test_files.rake
727
+ - lib/tasks/platform_gems.rake
726
728
  - lib/tasks/rust_backend.rake
727
729
  - readme-docs/advanced-features.adoc
728
730
  - readme-docs/api-usage.adoc