omnizip 0.4.7 → 0.4.9
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/.rubocop_todo.yml +3 -0
- data/CHANGELOG.md +22 -0
- data/lib/omnizip/archive_handlers/cpio_handler.rb +8 -0
- data/lib/omnizip/archive_handlers/iso_handler.rb +8 -0
- data/lib/omnizip/archive_handlers/rar_handler.rb +8 -0
- data/lib/omnizip/archive_handlers/rpm_handler.rb +3 -0
- data/lib/omnizip/archive_handlers/seven_zip_handler.rb +8 -0
- data/lib/omnizip/archive_handlers/tar_handler.rb +9 -1
- data/lib/omnizip/archive_handlers/xar_handler.rb +8 -0
- data/lib/omnizip/backends.rb +7 -4
- data/lib/omnizip/version.rb +1 -1
- data/lib/tasks/platform_gems.rake +54 -14
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 11fd728c2550d26fff721df376386c0f1b33bee6a025895770b214c0fe49e7a0
|
|
4
|
+
data.tar.gz: fa48858d122fb3a16460681678fa8db9f96382c2a5272dfab90b73b128a9baca
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b30e1ee39bd3eef72f02c06ae5a4fe10e84c3b71dc7efb5528593c8f092129572b43a6ca1e1a80469d528b8bc5692a3ef3bc9aff0e1a57245b2cb5a99017578c
|
|
7
|
+
data.tar.gz: 53b3fd01e1976a9cf6dba5d3c3745cd5a9994be42a98be4b7e6fe95ba60b2ba0282fe2a5a6936a4fa9486d4711b3bdf3b644451b014659c0a35ef80104c7f100
|
data/.rubocop_todo.yml
CHANGED
|
@@ -138,6 +138,9 @@ Metrics/AbcSize:
|
|
|
138
138
|
# AllowedMethods: refine
|
|
139
139
|
Metrics/BlockLength:
|
|
140
140
|
Max: 81
|
|
141
|
+
Exclude:
|
|
142
|
+
- "lib/tasks/platform_gems.rake"
|
|
143
|
+
- "spec/omnizip/archive_handlers/rust_tier_handlers_spec.rb"
|
|
141
144
|
|
|
142
145
|
# Offense count: 5
|
|
143
146
|
# Configuration parameters: CountBlocks, CountModifierForms.
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Fixed
|
|
11
|
+
- RPM archive-tier readiness: the dylib requirement is
|
|
12
|
+
**0.21.112**, not 0.21.111 — 0.21.111's `./`-stripping was half the
|
|
13
|
+
fix (the Ruby handler's names are ABSOLUTE, from the header's
|
|
14
|
+
DIRNAMES/BASENAMES; 0.21.112 normalizes the cpio names to
|
|
15
|
+
`/usr/…`). The tier spec version-guards accordingly, and with
|
|
16
|
+
0.21.112 the rpm tier is fully active (list stays Ruby by design;
|
|
17
|
+
read_entry is accelerated). Ships with the rubocop exclusion for
|
|
18
|
+
the tier spec that a CI-skipped merge dropped.
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- Archive-level tier for every handler: tar, cpio, iso, xar, 7z and
|
|
22
|
+
rar3/4/5 (with `password:` passthrough) route list(names) and
|
|
23
|
+
read_entry through the cdylib's whole-archive surface, falling back
|
|
24
|
+
to the Ruby readers on any Rust error or a missing library. rpm
|
|
25
|
+
rides the tier for read_entry once the dylib is ≥ 0.21.111 (which
|
|
26
|
+
strips the cpio `./` prefix so its entry names match the Ruby
|
|
27
|
+
handler's); rpm list and OLE stay pure-Ruby — OLE is a pinned model
|
|
28
|
+
divergence (Ruby lists top-level entries, Rust flattens the storage
|
|
29
|
+
tree), documented in the capability matrix and pinned by the new
|
|
30
|
+
cross-implementation differential spec.
|
|
31
|
+
|
|
10
32
|
### Added
|
|
11
33
|
- Prebuilt-binary distribution (parsanol model): platform gems
|
|
12
34
|
(x86_64/aarch64/arm Linux glibc+musl, arm64/x86_64 macOS,
|
|
@@ -20,6 +20,11 @@ module Omnizip
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def list(path, details: false, **_)
|
|
23
|
+
unless details
|
|
24
|
+
tier_names = Omnizip::Backends.archive_entry_names(path)
|
|
25
|
+
return tier_names if tier_names
|
|
26
|
+
end
|
|
27
|
+
|
|
23
28
|
entries = Omnizip::Formats::Cpio.list(path)
|
|
24
29
|
if details
|
|
25
30
|
entries.map do |e|
|
|
@@ -32,6 +37,9 @@ module Omnizip
|
|
|
32
37
|
end
|
|
33
38
|
|
|
34
39
|
def read_entry(path, entry_name, **_)
|
|
40
|
+
tier = Omnizip::Backends.archive_read_entry(path, entry_name)
|
|
41
|
+
return tier unless tier.nil?
|
|
42
|
+
|
|
35
43
|
entry = Omnizip::Formats::Cpio.list(path)
|
|
36
44
|
.find { |e| e.name == entry_name }
|
|
37
45
|
unless entry
|
|
@@ -20,6 +20,11 @@ module Omnizip
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def list(path, details: false, **_)
|
|
23
|
+
unless details
|
|
24
|
+
tier_names = Omnizip::Backends.archive_entry_names(path)
|
|
25
|
+
return tier_names if tier_names
|
|
26
|
+
end
|
|
27
|
+
|
|
23
28
|
entries = Omnizip::Formats::Iso.list(path)
|
|
24
29
|
if details
|
|
25
30
|
entries.map do |e|
|
|
@@ -32,6 +37,9 @@ module Omnizip
|
|
|
32
37
|
end
|
|
33
38
|
|
|
34
39
|
def read_entry(path, entry_name, **_)
|
|
40
|
+
tier = Omnizip::Backends.archive_read_entry(path, entry_name)
|
|
41
|
+
return tier unless tier.nil?
|
|
42
|
+
|
|
35
43
|
entry = Omnizip::Formats::Iso.list(path)
|
|
36
44
|
.find { |e| e.full_path == entry_name }
|
|
37
45
|
unless entry
|
|
@@ -29,6 +29,11 @@ module Omnizip
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def list(path, details: false, **_)
|
|
32
|
+
unless details
|
|
33
|
+
tier_names = Omnizip::Backends.archive_entry_names(path)
|
|
34
|
+
return tier_names if tier_names
|
|
35
|
+
end
|
|
36
|
+
|
|
32
37
|
reader = Omnizip::Formats::Rar::Reader.new(path).open
|
|
33
38
|
entries = reader.list_files
|
|
34
39
|
if details
|
|
@@ -43,6 +48,9 @@ module Omnizip
|
|
|
43
48
|
end
|
|
44
49
|
|
|
45
50
|
def read_entry(path, entry_name, password: nil, **_)
|
|
51
|
+
tier = Omnizip::Backends.archive_read_entry(path, entry_name, password: password)
|
|
52
|
+
return tier unless tier.nil?
|
|
53
|
+
|
|
46
54
|
Dir.mktmpdir("omnizip-rar-entry") do |dir|
|
|
47
55
|
dest = File.join(dir, "entry")
|
|
48
56
|
Omnizip::Formats::Rar::Decompressor.extract_entry(
|
|
@@ -29,6 +29,9 @@ module Omnizip
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def read_entry(path, entry_name, **_)
|
|
32
|
+
tier = Omnizip::Backends.archive_read_entry(path, entry_name)
|
|
33
|
+
return tier unless tier.nil?
|
|
34
|
+
|
|
32
35
|
Dir.mktmpdir("omnizip-rpm-entry") do |dir|
|
|
33
36
|
Omnizip::Formats::Rpm.extract(path, dir)
|
|
34
37
|
dest = File.join(dir, entry_name)
|
|
@@ -25,6 +25,11 @@ module Omnizip
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def list(path, details: false, **options)
|
|
28
|
+
unless details
|
|
29
|
+
tier_names = Omnizip::Backends.archive_entry_names(path, password: options[:password])
|
|
30
|
+
return tier_names if tier_names
|
|
31
|
+
end
|
|
32
|
+
|
|
28
33
|
with_reader(path, options) do |reader|
|
|
29
34
|
entries = reader.list_files
|
|
30
35
|
if details
|
|
@@ -40,6 +45,9 @@ module Omnizip
|
|
|
40
45
|
end
|
|
41
46
|
|
|
42
47
|
def read_entry(path, entry_name, **options)
|
|
48
|
+
tier = Omnizip::Backends.archive_read_entry(path, entry_name, password: options[:password])
|
|
49
|
+
return tier unless tier.nil?
|
|
50
|
+
|
|
43
51
|
with_reader(path, options) do |reader|
|
|
44
52
|
entry = reader.list_files.find { |e| e.name == entry_name }
|
|
45
53
|
raise Errno::ENOENT, "Entry not found: #{entry_name}" unless entry
|
|
@@ -22,6 +22,11 @@ module Omnizip
|
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def list(path, details: false, **_)
|
|
25
|
+
unless details
|
|
26
|
+
tier_names = Omnizip::Backends.archive_entry_names(path)
|
|
27
|
+
return tier_names if tier_names
|
|
28
|
+
end
|
|
29
|
+
|
|
25
30
|
entries = Omnizip::Formats::Tar.list(path)
|
|
26
31
|
if details
|
|
27
32
|
entries.map do |entry|
|
|
@@ -58,7 +63,10 @@ module Omnizip
|
|
|
58
63
|
end
|
|
59
64
|
end
|
|
60
65
|
|
|
61
|
-
def read_entry(path, entry_name)
|
|
66
|
+
def read_entry(path, entry_name, **_)
|
|
67
|
+
tier = Omnizip::Backends.archive_read_entry(path, entry_name)
|
|
68
|
+
return tier unless tier.nil?
|
|
69
|
+
|
|
62
70
|
data = nil
|
|
63
71
|
Omnizip::Formats::Tar.open(path) do |reader|
|
|
64
72
|
entry = reader.entries.find { |e| e.name == entry_name }
|
|
@@ -21,6 +21,11 @@ module Omnizip
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def list(path, details: false, **_)
|
|
24
|
+
unless details
|
|
25
|
+
tier_names = Omnizip::Backends.archive_entry_names(path)
|
|
26
|
+
return tier_names if tier_names
|
|
27
|
+
end
|
|
28
|
+
|
|
24
29
|
entries = Omnizip::Formats::Xar.list(path)
|
|
25
30
|
if details
|
|
26
31
|
entries.map do |e|
|
|
@@ -33,6 +38,9 @@ module Omnizip
|
|
|
33
38
|
end
|
|
34
39
|
|
|
35
40
|
def read_entry(path, entry_name, **_)
|
|
41
|
+
tier = Omnizip::Backends.archive_read_entry(path, entry_name)
|
|
42
|
+
return tier unless tier.nil?
|
|
43
|
+
|
|
36
44
|
Dir.mktmpdir("omnizip-xar-entry") do |dir|
|
|
37
45
|
Omnizip::Formats::Xar.extract(path, dir)
|
|
38
46
|
dest = File.join(dir, entry_name)
|
data/lib/omnizip/backends.rb
CHANGED
|
@@ -96,15 +96,18 @@ module Omnizip
|
|
|
96
96
|
|
|
97
97
|
# Whole-archive tier helpers: nil means "Rust unavailable or
|
|
98
98
|
# entry not found — caller falls back to the Ruby reader".
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
# Encrypted formats (rar, 7z) pass password:.
|
|
100
|
+
def archive_entry_names(path, password: nil)
|
|
101
|
+
Omnizip::Implementations::Rust::Archive.open(File.binread(path), password: password) do |a|
|
|
102
|
+
return a.entry_names
|
|
103
|
+
end
|
|
101
104
|
rescue Omnizip::Implementations::Rust::Archive::LibraryMissing, Omnizip::Implementations::Rust::Error, StandardError
|
|
102
105
|
nil
|
|
103
106
|
end
|
|
104
107
|
|
|
105
108
|
# rubocop:disable-next Lint/ReturnInVoidContext
|
|
106
|
-
def archive_read_entry(path, entry_name)
|
|
107
|
-
Omnizip::Implementations::Rust::Archive.open(File.binread(path)) do |a|
|
|
109
|
+
def archive_read_entry(path, entry_name, password: nil)
|
|
110
|
+
Omnizip::Implementations::Rust::Archive.open(File.binread(path), password: password) do |a|
|
|
108
111
|
idx = a.entry_names.index(entry_name)
|
|
109
112
|
return nil if idx.nil?
|
|
110
113
|
|
data/lib/omnizip/version.rb
CHANGED
|
@@ -42,26 +42,72 @@ namespace :platform_gems do
|
|
|
42
42
|
desc "Build platform gems for every tarball in DIR=libomnizip_ffi-<target>.tar.gz"
|
|
43
43
|
task :build do
|
|
44
44
|
dir = ENV.fetch("DIR") { abort "DIR=<artifacts dir> required" }
|
|
45
|
+
# Snapshot the pristine file list once. Gem::Specification.load
|
|
46
|
+
# caches by path and returns the SAME object on every call, so a
|
|
47
|
+
# per-call load + files += would leak the previous platform's
|
|
48
|
+
# cdylib into the next gem.
|
|
49
|
+
gem_root = File.expand_path("../..", __dir__)
|
|
50
|
+
base_spec = Gem::Specification.load(File.join(gem_root, "omnizip.gemspec"))
|
|
51
|
+
abort "omnizip.gemspec failed to load" unless base_spec
|
|
52
|
+
base_files = base_spec.files.select { |rel| File.file?(File.join(gem_root, rel)) }.freeze
|
|
53
|
+
|
|
45
54
|
Dir.glob(File.join(dir, "libomnizip_ffi-*.tar.gz")).each do |tarball|
|
|
46
55
|
target = File.basename(tarball, ".tar.gz").delete_prefix("libomnizip_ffi-")
|
|
47
56
|
platform = PLATFORM_GEM_TARGETS[target] or abort "no rubygems platform mapping for #{target}"
|
|
48
57
|
require "tmpdir"
|
|
49
58
|
Dir.mktmpdir do |tmp|
|
|
50
59
|
binary = extract_binary(tarball, tmp)
|
|
51
|
-
out = build_platform_gem(platform, binary)
|
|
60
|
+
out = build_platform_gem(platform, binary, base_files)
|
|
52
61
|
puts "built: #{out} (#{File.size(out)} bytes)"
|
|
53
62
|
end
|
|
54
63
|
end
|
|
55
64
|
end
|
|
56
65
|
|
|
66
|
+
desc "Push every already-built platform gem under pkg/ to rubygems (idempotent)"
|
|
67
|
+
task :release do
|
|
68
|
+
require "rake"
|
|
69
|
+
require "rubygems/package"
|
|
70
|
+
gem_root = File.expand_path("../..", __dir__)
|
|
71
|
+
pkg = File.join(gem_root, "pkg")
|
|
72
|
+
gems = Dir.glob(File.join(pkg, "omnizip-*.gem"))
|
|
73
|
+
abort "no platform gems under #{pkg} — run platform_gems:build first" if gems.empty?
|
|
74
|
+
|
|
75
|
+
# Pushes only what's already built in pkg/. Invoked by the
|
|
76
|
+
# platform-gem push job, which dispatches the trusted
|
|
77
|
+
# release.yml with next_version=skip + release_command override
|
|
78
|
+
# so the cimas reusable workflow authenticates via the
|
|
79
|
+
# already-trusted OIDC configuration and runs this task verbatim.
|
|
80
|
+
#
|
|
81
|
+
# Idempotent against re-push of an already-published version
|
|
82
|
+
# (cimas reusable handles "already been pushed" via the
|
|
83
|
+
# gem-idempotent-push-guard action).
|
|
84
|
+
gems.each do |path|
|
|
85
|
+
puts "pushing #{File.basename(path)}"
|
|
86
|
+
run_gem_push(path)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
57
90
|
def extract_binary(tarball, tmp)
|
|
58
91
|
system("tar", "-xzf", tarball, "-C", tmp) or abort "tar failed for #{tarball}"
|
|
59
92
|
Dir.glob(File.join(tmp, "*")).first or abort "empty tarball #{tarball}"
|
|
60
93
|
end
|
|
61
94
|
|
|
95
|
+
def run_gem_push(path)
|
|
96
|
+
require "rubygems/command/push_command"
|
|
97
|
+
cmd = Gem::Command::PushCommand.new
|
|
98
|
+
cmd.invoke("push", path)
|
|
99
|
+
rescue StandardError => e
|
|
100
|
+
raise if !/already been pushed|Repushing of gem versions is not allowed/i.match?(e.message)
|
|
101
|
+
|
|
102
|
+
warn "skip (already published): #{File.basename(path)}"
|
|
103
|
+
end
|
|
104
|
+
|
|
62
105
|
# Stage the tracked gem files plus the vendored cdylib, flip the
|
|
63
|
-
# gemspec platform, and build.
|
|
64
|
-
|
|
106
|
+
# gemspec platform, and build. `base_files` is the pristine
|
|
107
|
+
# gemspec file list (frozen); we ASSIGN a fresh list every call
|
|
108
|
+
# rather than mutating via +=, because Gem::Specification.load
|
|
109
|
+
# hands back a cached object.
|
|
110
|
+
def build_platform_gem(platform, dylib, base_files = nil)
|
|
65
111
|
require "fileutils"
|
|
66
112
|
require "rubygems/package"
|
|
67
113
|
require "tmpdir"
|
|
@@ -69,31 +115,25 @@ namespace :platform_gems do
|
|
|
69
115
|
gem_root = File.expand_path("../..", __dir__)
|
|
70
116
|
spec = Gem::Specification.load(File.join(gem_root, "omnizip.gemspec"))
|
|
71
117
|
abort "omnizip.gemspec failed to load" unless spec
|
|
118
|
+
base_files ||= spec.files.select { |rel| File.file?(File.join(gem_root, rel)) }
|
|
72
119
|
|
|
73
120
|
Dir.mktmpdir do |tmp|
|
|
74
121
|
stage = File.join(tmp, "stage")
|
|
75
|
-
|
|
76
|
-
src = File.join(gem_root, rel)
|
|
77
|
-
next unless File.file?(src)
|
|
78
|
-
|
|
122
|
+
base_files.each do |rel|
|
|
79
123
|
dst = File.join(stage, rel)
|
|
80
124
|
FileUtils.mkdir_p(File.dirname(dst))
|
|
81
|
-
FileUtils.cp(
|
|
125
|
+
FileUtils.cp(File.join(gem_root, rel), dst)
|
|
82
126
|
end
|
|
83
127
|
|
|
84
128
|
vendored = "vendor/libomnizip_ffi#{File.extname(dylib)}"
|
|
85
129
|
FileUtils.mkdir_p(File.join(stage, "vendor"))
|
|
86
130
|
FileUtils.cp(dylib, File.join(stage, vendored))
|
|
131
|
+
abort "staged cdylib missing: #{vendored}" unless File.file?(File.join(stage, vendored))
|
|
87
132
|
|
|
88
133
|
spec.platform = Gem::Platform.new(platform)
|
|
89
|
-
spec.files
|
|
134
|
+
spec.files = base_files + [vendored]
|
|
90
135
|
spec.test_files = []
|
|
91
136
|
|
|
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
137
|
Dir.chdir(stage) do
|
|
98
138
|
Gem::Package.build(spec)
|
|
99
139
|
end
|