omnizip 0.3.30 → 0.3.32
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/CHANGELOG.md +25 -0
- data/TODO.refactor/00-overview.md +1 -1
- data/TODO.refactor/13-lutaml-model-migration.md +27 -15
- data/lib/omnizip/cli.rb +32 -3
- data/lib/omnizip/convenience.rb +46 -0
- data/lib/omnizip/version.rb +1 -1
- data/lib/omnizip.rb +1 -0
- metadata +1 -2
- data/lib/omnizip/cli/shared.rb +0 -31
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a20cd2785f3068dabfe29b7cb3e9b88503b151839ea076fd4d4c727708e5a440
|
|
4
|
+
data.tar.gz: 7db78180133b7b7d3e62dff82588036c73dabc80c1957d892ffbff96fd83e657
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 601948e2be2303a5c82573728118fe4fdb6bd123ce983f6f92776373e3215e96c1b29ab02217356353a8978335af54233093ede1aeb9aa8665a57f1f189a9525
|
|
7
|
+
data.tar.gz: ac68a261028b8a92a948bb0f93caed9997e5e3d13c885962d1857104c65f16d2da2eba38996aac90fb0a17da57d9fa8b7e1c806956e22d65d36765ebcf9f84c7
|
data/CHANGELOG.md
CHANGED
|
@@ -7,8 +7,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Fixed
|
|
11
|
+
- The `omnizip` executable crashed on every invocation
|
|
12
|
+
(`uninitialized constant Omnizip::Cli`): the `Cli` autoload was
|
|
13
|
+
missing and the Thor command classes referenced
|
|
14
|
+
`Omnizip::Cli::Shared` mid-load, re-triggering the in-progress
|
|
15
|
+
autoload. The autoload exists now and Shared is defined ahead of
|
|
16
|
+
the command classes in `lib/omnizip/cli.rb` (its separate file is
|
|
17
|
+
gone). Verified: `omnizip version`, the documented
|
|
18
|
+
`compress/decompress output.lzma` round-trip (which also
|
|
19
|
+
interops with `xz --format=lzma` in both directions), and
|
|
20
|
+
`archive create backup.7z` producing an archive `7zz` validates.
|
|
21
|
+
|
|
10
22
|
## [0.3.31] - 2026-08-27
|
|
11
23
|
|
|
24
|
+
### Fixed
|
|
25
|
+
- `Omnizip.compress_file` now routes single-file compression by
|
|
26
|
+
output extension: `.gz`, `.bz2`, `.xz`, `.lzma` and `.lz` produce
|
|
27
|
+
the matching format instead of silently writing a ZIP under a
|
|
28
|
+
foreign extension (the documented
|
|
29
|
+
`compress_file('input.txt', 'output.lzma', algorithm: :lzma)`
|
|
30
|
+
example previously emitted `PK`-magic data). Unknown extensions
|
|
31
|
+
and explicit archive formats keep the previous behavior.
|
|
32
|
+
- CI: the Windows matrix no longer fails when choco's winrar
|
|
33
|
+
download 404s (RAR specs skip when it is absent).
|
|
34
|
+
|
|
35
|
+
## [0.3.30] - 2026-08-27
|
|
36
|
+
|
|
12
37
|
### Changed
|
|
13
38
|
- Re-enabled LZMA2 in the 7-Zip header-encryption and split-archive
|
|
14
39
|
specs (the multi-chunk encoder landed in 0.3.19; the specs had
|
|
@@ -32,7 +32,7 @@ as absolute rules:
|
|
|
32
32
|
| 10 | `10-format-detector-ocp.md` | medium | **DONE** |
|
|
33
33
|
| 11 | `11-convenience-decoupling.md` | medium | **DONE** (ArchiveHandler dispatcher + ZipHandler + TarHandler) |
|
|
34
34
|
| 12 | `12-thread-safety.md` | covered by 01 | n/a |
|
|
35
|
-
| 13 | `13-lutaml-model-migration.md` | medium | **
|
|
35
|
+
| 13 | `13-lutaml-model-migration.md` | medium | **DONE** — six models migrated; follow-ups 2+3 landed in 0.3.28; 1 and 4 decided (deferred rename / migration declined with reasons) |
|
|
36
36
|
| 14 | `14-add-missing-specs.md` | high | **DONE** |
|
|
37
37
|
|
|
38
38
|
## Anti-pattern counts (lib/)
|
|
@@ -129,18 +129,30 @@ is the intended end state, not unfinished work.
|
|
|
129
129
|
|
|
130
130
|
## Follow-up work
|
|
131
131
|
|
|
132
|
-
1. **Rename the 17
|
|
133
|
-
|
|
134
|
-
`to_report` for the computed ones, `to_tag_map` /
|
|
135
|
-
for projections, `to_xml_attributes` / `to_fields`
|
|
136
|
-
builders. Each rename is
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
3. **
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
132
|
+
1. **Rename the 17 — DECIDED: deferred to a deliberate major/minor
|
|
133
|
+
release.** The names below remain the plan if that release
|
|
134
|
+
happens: `to_report` for the computed ones, `to_tag_map` /
|
|
135
|
+
`to_attributes` for projections, `to_xml_attributes` / `to_fields`
|
|
136
|
+
for wire-format builders. Each rename is a public-API break
|
|
137
|
+
(every one of the 17 is a public class method), so it cannot ship
|
|
138
|
+
silently in a patch; the 17 staying is the intended end state for
|
|
139
|
+
now, per "Why 17 stay" above.
|
|
140
|
+
2. **DONE (0.3.28, PR #42).** `apply` fixed in both classes — all
|
|
141
|
+
three options models now share the tested
|
|
142
|
+
`Models::AttributeApply` concern, which also delivers (3).
|
|
143
|
+
3. **DONE (0.3.28, PR #42)** — see (2).
|
|
144
|
+
4. **Considered — decided against, with reasons.**
|
|
145
|
+
- `FilterConfig` is a behavior-heavy domain object, not a
|
|
146
|
+
serialization model: `filter_instance` reaches into
|
|
147
|
+
`FilterRegistry`, `id_for_format`/`bcj?`/`delta?` are domain
|
|
148
|
+
queries, `properties` defaults to a binary String (lutaml's
|
|
149
|
+
`:string` is UTF-8-oriented, so the attribute would need a
|
|
150
|
+
custom type), and initialization accepts two alias keys
|
|
151
|
+
(`:name`/`:name_sym`). Its `to_h` is a projection with no
|
|
152
|
+
round-trip consumer. Migration would fight the framework to
|
|
153
|
+
achieve nothing the class needs.
|
|
154
|
+
- The profile classes are abstract domain objects: subclasses
|
|
155
|
+
override `suitable_for?`, `apply_to` mutates an options object,
|
|
156
|
+
five validators run at construction, and `to_h` coexists with
|
|
157
|
+
`to_s`/`inspect` as display projections. No wire format round
|
|
158
|
+
trips them. Same verdict.
|
data/lib/omnizip/cli.rb
CHANGED
|
@@ -19,9 +19,38 @@
|
|
|
19
19
|
require "thor"
|
|
20
20
|
|
|
21
21
|
module Omnizip
|
|
22
|
+
# Shared helpers used by the Thor command groups defined below
|
|
23
|
+
# (ProfileCommands, ArchiveCommands, Cli). Defined here because the
|
|
24
|
+
# command classes include it at class-body time; a separate file
|
|
25
|
+
# under Omnizip::Cli would re-trigger this file's autoload
|
|
26
|
+
# mid-load.
|
|
27
|
+
module Shared
|
|
28
|
+
# Print a formatted error message and exit nonzero.
|
|
29
|
+
#
|
|
30
|
+
# @param error [StandardError] the error to display
|
|
31
|
+
def handle_error(error)
|
|
32
|
+
warn Omnizip::CliOutputFormatter.format_error(error)
|
|
33
|
+
exit 1
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Format a byte count with a binary-unit suffix.
|
|
37
|
+
#
|
|
38
|
+
# @param bytes [Integer] the byte count
|
|
39
|
+
# @return [String] human-readable size (e.g. "1.5 MB")
|
|
40
|
+
def format_bytes(bytes)
|
|
41
|
+
return "0 B" if bytes.zero?
|
|
42
|
+
|
|
43
|
+
units = %w[B KB MB GB TB]
|
|
44
|
+
exp = (Math.log(bytes) / Math.log(1024)).to_i
|
|
45
|
+
exp = [exp, units.size - 1].min
|
|
46
|
+
|
|
47
|
+
"%.1f %s" % [bytes.to_f / (1024**exp), units[exp]]
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
22
51
|
# Profile commands subcommand group
|
|
23
52
|
class ProfileCommands < Thor
|
|
24
|
-
include
|
|
53
|
+
include Shared
|
|
25
54
|
|
|
26
55
|
class << self
|
|
27
56
|
def exit_on_failure?
|
|
@@ -69,7 +98,7 @@ module Omnizip
|
|
|
69
98
|
|
|
70
99
|
# Archive commands subcommand group
|
|
71
100
|
class ArchiveCommands < Thor
|
|
72
|
-
include
|
|
101
|
+
include Shared
|
|
73
102
|
|
|
74
103
|
class << self
|
|
75
104
|
def exit_on_failure?
|
|
@@ -298,7 +327,7 @@ module Omnizip
|
|
|
298
327
|
# Provides Thor-based CLI commands for compressing and decompressing
|
|
299
328
|
# files using various compression algorithms.
|
|
300
329
|
class Cli < Thor
|
|
301
|
-
include
|
|
330
|
+
include Shared
|
|
302
331
|
|
|
303
332
|
class << self
|
|
304
333
|
def exit_on_failure?
|
data/lib/omnizip/convenience.rb
CHANGED
|
@@ -31,6 +31,15 @@ module Omnizip
|
|
|
31
31
|
return Omnizip::Chunked.compress_file(input_path, output_path, **options)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
+
# Single-file compression formats route by output extension
|
|
35
|
+
# (unless an archive format was requested explicitly): writing
|
|
36
|
+
# output.lzma through the archive path silently produced a ZIP
|
|
37
|
+
# under a foreign extension.
|
|
38
|
+
if format == DEFAULT_FORMAT && (handler = single_file_handler(output_path))
|
|
39
|
+
handler.call(input_path, output_path, options)
|
|
40
|
+
return output_path
|
|
41
|
+
end
|
|
42
|
+
|
|
34
43
|
Omnizip::ArchiveHandler.for(format).create(output_path) do |archive|
|
|
35
44
|
archive.add(::File.basename(input_path), input_path)
|
|
36
45
|
end
|
|
@@ -160,6 +169,43 @@ module Omnizip
|
|
|
160
169
|
Omnizip::Formats::Rar.create(archive_path, options, &block)
|
|
161
170
|
end
|
|
162
171
|
|
|
172
|
+
# Extension -> single-file compressor map. Each lambda takes
|
|
173
|
+
# (input_path, output_path, options). These formats are streams,
|
|
174
|
+
# not archives, so they bypass ArchiveHandler.
|
|
175
|
+
SINGLE_FILE_COMPRESSORS = {
|
|
176
|
+
".gz" => lambda do |input, output, options|
|
|
177
|
+
Omnizip::Formats::Gzip.compress(input, output, options)
|
|
178
|
+
end,
|
|
179
|
+
".bz2" => lambda do |input, output, options|
|
|
180
|
+
Omnizip::Formats::Bzip2File.compress(input, output, options)
|
|
181
|
+
end,
|
|
182
|
+
".xz" => lambda do |input, output, options|
|
|
183
|
+
Omnizip::Formats::Xz.create(::File.binread(input), output, options)
|
|
184
|
+
end,
|
|
185
|
+
".lzma" => lambda do |input, output, options|
|
|
186
|
+
::File.open(input, "rb") do |input_io|
|
|
187
|
+
::File.open(output, "wb") do |output_io|
|
|
188
|
+
Omnizip::Formats::LzmaAlone.compress_stream(input_io, output_io,
|
|
189
|
+
options)
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end,
|
|
193
|
+
".lz" => lambda do |input, output, options|
|
|
194
|
+
::File.open(input, "rb") do |input_io|
|
|
195
|
+
::File.open(output, "wb") do |output_io|
|
|
196
|
+
Omnizip::Formats::Lzip.compress_stream(input_io, output_io,
|
|
197
|
+
options)
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end,
|
|
201
|
+
}.freeze
|
|
202
|
+
|
|
203
|
+
# The single-file compressor matching the output extension, or nil.
|
|
204
|
+
def single_file_handler(output_path)
|
|
205
|
+
ext = ::File.extname(output_path).downcase
|
|
206
|
+
SINGLE_FILE_COMPRESSORS[ext]
|
|
207
|
+
end
|
|
208
|
+
|
|
163
209
|
private
|
|
164
210
|
|
|
165
211
|
def require_archive!(archive_path)
|
data/lib/omnizip/version.rb
CHANGED
data/lib/omnizip.rb
CHANGED
|
@@ -67,6 +67,7 @@ module Omnizip
|
|
|
67
67
|
autoload :Profiler, "omnizip/profiler"
|
|
68
68
|
autoload :Commands, "omnizip/commands"
|
|
69
69
|
autoload :CliOutputFormatter, "omnizip/cli/output_formatter"
|
|
70
|
+
autoload :Cli, "omnizip/cli"
|
|
70
71
|
|
|
71
72
|
# Implementation namespaces. Each namespace file declares autoloads
|
|
72
73
|
# for its concrete classes. The classes self-register with their
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: omnizip
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.32
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -339,7 +339,6 @@ files:
|
|
|
339
339
|
- lib/omnizip/chunked/writer.rb
|
|
340
340
|
- lib/omnizip/cli.rb
|
|
341
341
|
- lib/omnizip/cli/output_formatter.rb
|
|
342
|
-
- lib/omnizip/cli/shared.rb
|
|
343
342
|
- lib/omnizip/commands.rb
|
|
344
343
|
- lib/omnizip/commands/.keep
|
|
345
344
|
- lib/omnizip/commands/archive_create_command.rb
|
data/lib/omnizip/cli/shared.rb
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Omnizip
|
|
4
|
-
class Cli
|
|
5
|
-
# Shared helpers used by the Thor command groups defined in
|
|
6
|
-
# lib/omnizip/cli.rb (ProfileCommands, ArchiveCommands, Cli).
|
|
7
|
-
module Shared
|
|
8
|
-
# Print a formatted error message and exit nonzero.
|
|
9
|
-
#
|
|
10
|
-
# @param error [StandardError] the error to display
|
|
11
|
-
def handle_error(error)
|
|
12
|
-
warn Omnizip::CliOutputFormatter.format_error(error)
|
|
13
|
-
exit 1
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# Format a byte count with a binary-unit suffix.
|
|
17
|
-
#
|
|
18
|
-
# @param bytes [Integer] the byte count
|
|
19
|
-
# @return [String] human-readable size (e.g. "1.5 MB")
|
|
20
|
-
def format_bytes(bytes)
|
|
21
|
-
return "0 B" if bytes.zero?
|
|
22
|
-
|
|
23
|
-
units = %w[B KB MB GB TB]
|
|
24
|
-
exp = (Math.log(bytes) / Math.log(1024)).to_i
|
|
25
|
-
exp = [exp, units.size - 1].min
|
|
26
|
-
|
|
27
|
-
"%.1f %s" % [bytes.to_f / (1024**exp), units[exp]]
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|