omnizip 0.4.7-x86_64-linux
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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +32 -0
- data/.rubocop_todo.yml +293 -0
- data/CHANGELOG.md +1647 -0
- data/CONTEXT.md +68 -0
- data/COPYING +502 -0
- data/Gemfile +19 -0
- data/LICENSE +12 -0
- data/README.adoc +1327 -0
- data/Rakefile +15 -0
- data/TODO.refactor/00-overview.md +67 -0
- data/TODO.refactor/01-registry-base-class.md +81 -0
- data/TODO.refactor/02-error-hierarchy.md +57 -0
- data/TODO.refactor/03-autoload-entry-point.md +69 -0
- data/TODO.refactor/04-filter-base-consolidation.md +49 -0
- data/TODO.refactor/05-send-private-methods.md +64 -0
- data/TODO.refactor/06-instance-variable-access.md +69 -0
- data/TODO.refactor/07-respond-to-replacement.md +237 -0
- data/TODO.refactor/08-spec-doubles.md +27 -0
- data/TODO.refactor/09-cli-shared-module.md +35 -0
- data/TODO.refactor/10-format-detector-ocp.md +34 -0
- data/TODO.refactor/11-convenience-decoupling.md +38 -0
- data/TODO.refactor/12-thread-safety.md +8 -0
- data/TODO.refactor/13-lutaml-model-migration.md +158 -0
- data/TODO.refactor/14-add-missing-specs.md +25 -0
- data/benchmark/README.md +260 -0
- data/benchmark/benchmark_suite.rb +125 -0
- data/benchmark/compression_bench.rb +181 -0
- data/benchmark/filter_bench.rb +180 -0
- data/benchmark/models/benchmark_result.rb +59 -0
- data/benchmark/models/comparison_result.rb +69 -0
- data/benchmark/profile_suite.rb +167 -0
- data/benchmark/reporter.rb +150 -0
- data/benchmark/run_benchmarks.rb +66 -0
- data/benchmark/test_data.rb +137 -0
- data/config/formats/rar3_spec.yml +92 -0
- data/config/formats/rar5_spec.yml +102 -0
- data/docs/.github/workflows/docs.yml +142 -0
- data/docs/.gitignore +21 -0
- data/docs/.lychee.toml +67 -0
- data/docs/Gemfile +13 -0
- data/docs/RAR_WRITE_SUPPORT.md +26 -0
- data/docs/README.md +101 -0
- data/docs/_config.yml +112 -0
- data/docs/assets/logo.svg +1 -0
- data/docs/assets/omnizip-logo.pdf +1540 -11
- data/docs/comparison/feature-matrix.adoc +694 -0
- data/docs/comparison/index.adoc +113 -0
- data/docs/comparison/vs-7zip.adoc +309 -0
- data/docs/comparison/vs-peazip.adoc +77 -0
- data/docs/comparison/vs-rubyzip.adoc +342 -0
- data/docs/comparison/vs-winrar.adoc +100 -0
- data/docs/compatibility.adoc +579 -0
- data/docs/concepts/index.adoc +129 -0
- data/docs/developer/architecture.adoc +256 -0
- data/docs/developer/contributing.adoc +158 -0
- data/docs/developer/index.adoc +25 -0
- data/docs/developer/testing.adoc +212 -0
- data/docs/getting-started/basic-usage.adoc +263 -0
- data/docs/getting-started/index.adoc +42 -0
- data/docs/getting-started/installation.adoc +138 -0
- data/docs/getting-started/quick-start.adoc +183 -0
- data/docs/getting-started/your-first-archive.adoc +219 -0
- data/docs/guides/advanced-features/encryption.adoc +277 -0
- data/docs/guides/advanced-features/index.adoc +59 -0
- data/docs/guides/advanced-features/parallel-processing.adoc +144 -0
- data/docs/guides/advanced-features/progress-tracking.adoc +124 -0
- data/docs/guides/advanced-features/streaming.adoc +142 -0
- data/docs/guides/archive-formats/gzip-format.adoc +105 -0
- data/docs/guides/archive-formats/index.adoc +160 -0
- data/docs/guides/archive-formats/ole-format.adoc +151 -0
- data/docs/guides/archive-formats/rar-format.adoc +104 -0
- data/docs/guides/archive-formats/rar5.adoc +521 -0
- data/docs/guides/archive-formats/rpm-format.adoc +108 -0
- data/docs/guides/archive-formats/seven-zip-format.adoc +35 -0
- data/docs/guides/archive-formats/tar-format.adoc +106 -0
- data/docs/guides/archive-formats/xz-format.adoc +118 -0
- data/docs/guides/archive-formats/zip-format.adoc +35 -0
- data/docs/guides/compression-algorithms/bzip2.adoc +114 -0
- data/docs/guides/compression-algorithms/deflate.adoc +313 -0
- data/docs/guides/compression-algorithms/index.adoc +190 -0
- data/docs/guides/compression-algorithms/lzma.adoc +394 -0
- data/docs/guides/compression-algorithms/lzma2.adoc +244 -0
- data/docs/guides/compression-algorithms/ppmd.adoc +313 -0
- data/docs/guides/compression-algorithms/zstandard.adoc +296 -0
- data/docs/guides/creating-archives.adoc +348 -0
- data/docs/guides/extracting-archives.adoc +53 -0
- data/docs/guides/format-conversion.adoc +64 -0
- data/docs/guides/index.adoc +49 -0
- data/docs/guides/migration-rubyzip.adoc +217 -0
- data/docs/guides/parity-archives.adoc +605 -0
- data/docs/guides/performance-tuning.adoc +88 -0
- data/docs/index.adoc +228 -0
- data/docs/lychee.toml +67 -0
- data/docs/reference/api/overview.adoc +187 -0
- data/docs/reference/cli/compress-command.adoc +114 -0
- data/docs/reference/cli/overview.adoc +140 -0
- data/docs/reference/index.adoc +26 -0
- data/docs/resources/faq.adoc +185 -0
- data/docs/resources/quick-reference.adoc +222 -0
- data/docs/rust-backend.md +0 -0
- data/docs/troubleshooting/index.adoc +207 -0
- data/docs/xar_format.md +216 -0
- data/examples/api_comparison.rb +205 -0
- data/examples/deflate64_example.rb +96 -0
- data/examples/par2_demo.rb +121 -0
- data/examples/quick_start_native.rb +150 -0
- data/examples/quick_start_rubyzip.rb +115 -0
- data/examples/rubyzip_compatibility_demo.rb +194 -0
- data/exe/omnizip +27 -0
- data/lib/omnizip/algorithm.rb +176 -0
- data/lib/omnizip/algorithm_registry.rb +65 -0
- data/lib/omnizip/algorithms/.keep +0 -0
- data/lib/omnizip/algorithms/bzip2/bwt.rb +236 -0
- data/lib/omnizip/algorithms/bzip2/bz2.rb +687 -0
- data/lib/omnizip/algorithms/bzip2/rle.rb +146 -0
- data/lib/omnizip/algorithms/bzip2.rb +108 -0
- data/lib/omnizip/algorithms/deflate/constants.rb +28 -0
- data/lib/omnizip/algorithms/deflate/decoder.rb +37 -0
- data/lib/omnizip/algorithms/deflate/encoder.rb +45 -0
- data/lib/omnizip/algorithms/deflate.rb +135 -0
- data/lib/omnizip/algorithms/deflate64/constants.rb +45 -0
- data/lib/omnizip/algorithms/deflate64/decoder.rb +151 -0
- data/lib/omnizip/algorithms/deflate64/encoder.rb +95 -0
- data/lib/omnizip/algorithms/deflate64/huffman_coder.rb +352 -0
- data/lib/omnizip/algorithms/deflate64/lz77_encoder.rb +140 -0
- data/lib/omnizip/algorithms/deflate64.rb +118 -0
- data/lib/omnizip/algorithms/lzma/bit_model.rb +120 -0
- data/lib/omnizip/algorithms/lzma/constants.rb +112 -0
- data/lib/omnizip/algorithms/lzma/decoder.rb +146 -0
- data/lib/omnizip/algorithms/lzma/dictionary.rb +70 -0
- data/lib/omnizip/algorithms/lzma/distance_coder.rb +326 -0
- data/lib/omnizip/algorithms/lzma/encoder.rb +139 -0
- data/lib/omnizip/algorithms/lzma/length_coder.rb +172 -0
- data/lib/omnizip/algorithms/lzma/literal_decoder.rb +204 -0
- data/lib/omnizip/algorithms/lzma/literal_encoder.rb +208 -0
- data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +368 -0
- data/lib/omnizip/algorithms/lzma/lzma1_encoder.rb +105 -0
- data/lib/omnizip/algorithms/lzma/lzma_alone_decoder.rb +194 -0
- data/lib/omnizip/algorithms/lzma/lzma_state.rb +128 -0
- data/lib/omnizip/algorithms/lzma/match.rb +32 -0
- data/lib/omnizip/algorithms/lzma/match_finder.rb +233 -0
- data/lib/omnizip/algorithms/lzma/match_finder_config.rb +142 -0
- data/lib/omnizip/algorithms/lzma/match_finder_factory.rb +84 -0
- data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +159 -0
- data/lib/omnizip/algorithms/lzma/probability_models.rb +72 -0
- data/lib/omnizip/algorithms/lzma/range_coder.rb +82 -0
- data/lib/omnizip/algorithms/lzma/range_decoder.rb +274 -0
- data/lib/omnizip/algorithms/lzma/range_encoder.rb +202 -0
- data/lib/omnizip/algorithms/lzma/state.rb +127 -0
- data/lib/omnizip/algorithms/lzma/xz_buffered_range_encoder.rb +323 -0
- data/lib/omnizip/algorithms/lzma/xz_encoder.rb +420 -0
- data/lib/omnizip/algorithms/lzma/xz_encoder_fast.rb +640 -0
- data/lib/omnizip/algorithms/lzma/xz_match_finder_adapter.rb +224 -0
- data/lib/omnizip/algorithms/lzma/xz_price_calculator.rb +167 -0
- data/lib/omnizip/algorithms/lzma/xz_probability_models.rb +258 -0
- data/lib/omnizip/algorithms/lzma/xz_range_encoder.rb +223 -0
- data/lib/omnizip/algorithms/lzma/xz_range_encoder_exact.rb +314 -0
- data/lib/omnizip/algorithms/lzma/xz_state.rb +108 -0
- data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +1311 -0
- data/lib/omnizip/algorithms/lzma.rb +266 -0
- data/lib/omnizip/algorithms/lzma2/chunk_manager.rb +180 -0
- data/lib/omnizip/algorithms/lzma2/constants.rb +38 -0
- data/lib/omnizip/algorithms/lzma2/encoder.rb +145 -0
- data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +165 -0
- data/lib/omnizip/algorithms/lzma2/properties.rb +179 -0
- data/lib/omnizip/algorithms/lzma2/simple_lzma2_encoder.rb +122 -0
- data/lib/omnizip/algorithms/lzma2/xz_encoder_adapter.rb +85 -0
- data/lib/omnizip/algorithms/lzma2.rb +133 -0
- data/lib/omnizip/algorithms/ppmd7/constants.rb +74 -0
- data/lib/omnizip/algorithms/ppmd7/context.rb +151 -0
- data/lib/omnizip/algorithms/ppmd7/decoder.rb +127 -0
- data/lib/omnizip/algorithms/ppmd7/encoder.rb +153 -0
- data/lib/omnizip/algorithms/ppmd7/model.rb +245 -0
- data/lib/omnizip/algorithms/ppmd7/symbol_state.rb +57 -0
- data/lib/omnizip/algorithms/ppmd7.rb +146 -0
- data/lib/omnizip/algorithms/ppmd8/constants.rb +61 -0
- data/lib/omnizip/algorithms/ppmd8/context.rb +32 -0
- data/lib/omnizip/algorithms/ppmd8/decoder.rb +104 -0
- data/lib/omnizip/algorithms/ppmd8/encoder.rb +135 -0
- data/lib/omnizip/algorithms/ppmd8/model.rb +246 -0
- data/lib/omnizip/algorithms/ppmd8/restoration_method.rb +78 -0
- data/lib/omnizip/algorithms/ppmd8.rb +122 -0
- data/lib/omnizip/algorithms/ppmd_base.rb +142 -0
- data/lib/omnizip/algorithms/registration.rb +28 -0
- data/lib/omnizip/algorithms/zstandard/constants.rb +158 -0
- data/lib/omnizip/algorithms/zstandard/decoder.rb +249 -0
- data/lib/omnizip/algorithms/zstandard/dictionary.rb +73 -0
- data/lib/omnizip/algorithms/zstandard/encoder.rb +294 -0
- data/lib/omnizip/algorithms/zstandard/frame/block.rb +143 -0
- data/lib/omnizip/algorithms/zstandard/frame/header.rb +233 -0
- data/lib/omnizip/algorithms/zstandard/frame.rb +33 -0
- data/lib/omnizip/algorithms/zstandard/fse/bitstream.rb +183 -0
- data/lib/omnizip/algorithms/zstandard/fse/encoder.rb +534 -0
- data/lib/omnizip/algorithms/zstandard/fse/interleaved.rb +92 -0
- data/lib/omnizip/algorithms/zstandard/fse/table.rb +188 -0
- data/lib/omnizip/algorithms/zstandard/fse/table_description.rb +203 -0
- data/lib/omnizip/algorithms/zstandard/fse.rb +53 -0
- data/lib/omnizip/algorithms/zstandard/huffman.rb +276 -0
- data/lib/omnizip/algorithms/zstandard/huffman_encoder.rb +327 -0
- data/lib/omnizip/algorithms/zstandard/ldm.rb +121 -0
- data/lib/omnizip/algorithms/zstandard/literals.rb +241 -0
- data/lib/omnizip/algorithms/zstandard/literals_encoder.rb +96 -0
- data/lib/omnizip/algorithms/zstandard/match_finder.rb +483 -0
- data/lib/omnizip/algorithms/zstandard/sequences.rb +350 -0
- data/lib/omnizip/algorithms/zstandard/sequences_encoder.rb +333 -0
- data/lib/omnizip/algorithms/zstandard/xxhash.rb +159 -0
- data/lib/omnizip/algorithms/zstandard.rb +210 -0
- data/lib/omnizip/algorithms.rb +35 -0
- data/lib/omnizip/archive/builder.rb +48 -0
- data/lib/omnizip/archive/reader_session.rb +67 -0
- data/lib/omnizip/archive.rb +86 -0
- data/lib/omnizip/archive_handler.rb +82 -0
- data/lib/omnizip/archive_handlers/cpio_handler.rb +47 -0
- data/lib/omnizip/archive_handlers/iso_handler.rb +54 -0
- data/lib/omnizip/archive_handlers/ole_handler.rb +37 -0
- data/lib/omnizip/archive_handlers/rar_handler.rb +96 -0
- data/lib/omnizip/archive_handlers/rpm_handler.rb +45 -0
- data/lib/omnizip/archive_handlers/seven_zip_handler.rb +89 -0
- data/lib/omnizip/archive_handlers/tar_handler.rb +75 -0
- data/lib/omnizip/archive_handlers/xar_handler.rb +49 -0
- data/lib/omnizip/archive_handlers/zip_handler.rb +115 -0
- data/lib/omnizip/archive_handlers.rb +18 -0
- data/lib/omnizip/backends.rb +160 -0
- data/lib/omnizip/buffer/memory_archive.rb +246 -0
- data/lib/omnizip/buffer/memory_extractor.rb +234 -0
- data/lib/omnizip/buffer/seven_zip_bridge.rb +171 -0
- data/lib/omnizip/buffer.rb +187 -0
- data/lib/omnizip/checksum_registry.rb +41 -0
- data/lib/omnizip/checksums/crc32.rb +101 -0
- data/lib/omnizip/checksums/crc64.rb +102 -0
- data/lib/omnizip/checksums/crc_base.rb +158 -0
- data/lib/omnizip/checksums/registration.rb +16 -0
- data/lib/omnizip/checksums/verifier.rb +130 -0
- data/lib/omnizip/checksums.rb +11 -0
- data/lib/omnizip/chunked/memory_manager.rb +194 -0
- data/lib/omnizip/chunked/reader.rb +78 -0
- data/lib/omnizip/chunked/writer.rb +123 -0
- data/lib/omnizip/chunked.rb +123 -0
- data/lib/omnizip/cli/output_formatter.rb +112 -0
- data/lib/omnizip/cli.rb +604 -0
- data/lib/omnizip/commands/.keep +0 -0
- data/lib/omnizip/commands/archive_create_command.rb +245 -0
- data/lib/omnizip/commands/archive_extract_command.rb +231 -0
- data/lib/omnizip/commands/archive_list_command.rb +204 -0
- data/lib/omnizip/commands/archive_repair_command.rb +129 -0
- data/lib/omnizip/commands/archive_verify_command.rb +115 -0
- data/lib/omnizip/commands/compress_command.rb +115 -0
- data/lib/omnizip/commands/decompress_command.rb +149 -0
- data/lib/omnizip/commands/list_command.rb +51 -0
- data/lib/omnizip/commands/metadata_command.rb +215 -0
- data/lib/omnizip/commands/parity_create_command.rb +114 -0
- data/lib/omnizip/commands/parity_repair_command.rb +120 -0
- data/lib/omnizip/commands/parity_verify_command.rb +122 -0
- data/lib/omnizip/commands/profile_list_command.rb +54 -0
- data/lib/omnizip/commands/profile_show_command.rb +44 -0
- data/lib/omnizip/commands.rb +21 -0
- data/lib/omnizip/convenience.rb +389 -0
- data/lib/omnizip/converter/conversion_registry.rb +50 -0
- data/lib/omnizip/converter/conversion_strategy.rb +108 -0
- data/lib/omnizip/converter/extract_repack_strategy.rb +51 -0
- data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +43 -0
- data/lib/omnizip/converter/zip_to_seven_zip_strategy.rb +54 -0
- data/lib/omnizip/converter.rb +124 -0
- data/lib/omnizip/crypto/aes256/cipher.rb +104 -0
- data/lib/omnizip/crypto/aes256/constants.rb +28 -0
- data/lib/omnizip/crypto/aes256/key_derivation.rb +100 -0
- data/lib/omnizip/crypto/aes256.rb +102 -0
- data/lib/omnizip/crypto.rb +11 -0
- data/lib/omnizip/entry.rb +44 -0
- data/lib/omnizip/error.rb +110 -0
- data/lib/omnizip/eta/exponential_smoothing_estimator.rb +95 -0
- data/lib/omnizip/eta/moving_average_estimator.rb +96 -0
- data/lib/omnizip/eta/rate_calculator.rb +104 -0
- data/lib/omnizip/eta/sample_history.rb +143 -0
- data/lib/omnizip/eta/time_estimator.rb +106 -0
- data/lib/omnizip/eta.rb +68 -0
- data/lib/omnizip/extraction/filter_chain.rb +179 -0
- data/lib/omnizip/extraction/glob_pattern.rb +140 -0
- data/lib/omnizip/extraction/pattern_matcher.rb +66 -0
- data/lib/omnizip/extraction/predicate_pattern.rb +52 -0
- data/lib/omnizip/extraction/regex_pattern.rb +50 -0
- data/lib/omnizip/extraction/selective_extractor.rb +247 -0
- data/lib/omnizip/extraction.rb +115 -0
- data/lib/omnizip/file_type/mime_classifier.rb +144 -0
- data/lib/omnizip/file_type.rb +117 -0
- data/lib/omnizip/filter.rb +141 -0
- data/lib/omnizip/filter_pipeline.rb +108 -0
- data/lib/omnizip/filter_registry.rb +113 -0
- data/lib/omnizip/filters/bcj.rb +277 -0
- data/lib/omnizip/filters/bcj2/constants.rb +53 -0
- data/lib/omnizip/filters/bcj2/decoder.rb +263 -0
- data/lib/omnizip/filters/bcj2/encoder.rb +58 -0
- data/lib/omnizip/filters/bcj2/stream_data.rb +91 -0
- data/lib/omnizip/filters/bcj2.rb +93 -0
- data/lib/omnizip/filters/bcj_arm.rb +174 -0
- data/lib/omnizip/filters/bcj_arm64.rb +242 -0
- data/lib/omnizip/filters/bcj_ia64.rb +194 -0
- data/lib/omnizip/filters/bcj_ppc.rb +188 -0
- data/lib/omnizip/filters/bcj_sparc.rb +174 -0
- data/lib/omnizip/filters/bcj_x86.rb +191 -0
- data/lib/omnizip/filters/delta.rb +195 -0
- data/lib/omnizip/filters/xz_delta.rb +258 -0
- data/lib/omnizip/filters.rb +20 -0
- data/lib/omnizip/format_detector.rb +166 -0
- data/lib/omnizip/formats/.keep +0 -0
- data/lib/omnizip/formats/bzip2_file.rb +159 -0
- data/lib/omnizip/formats/cpio/bounded_io.rb +66 -0
- data/lib/omnizip/formats/cpio/constants.rb +55 -0
- data/lib/omnizip/formats/cpio/entry.rb +389 -0
- data/lib/omnizip/formats/cpio/reader.rb +194 -0
- data/lib/omnizip/formats/cpio/writer.rb +232 -0
- data/lib/omnizip/formats/cpio.rb +132 -0
- data/lib/omnizip/formats/format_spec_loader.rb +228 -0
- data/lib/omnizip/formats/gzip.rb +236 -0
- data/lib/omnizip/formats/iso/directory_builder.rb +321 -0
- data/lib/omnizip/formats/iso/directory_record.rb +162 -0
- data/lib/omnizip/formats/iso/joliet.rb +204 -0
- data/lib/omnizip/formats/iso/path_table.rb +125 -0
- data/lib/omnizip/formats/iso/reader.rb +194 -0
- data/lib/omnizip/formats/iso/rock_ridge.rb +349 -0
- data/lib/omnizip/formats/iso/volume_builder.rb +319 -0
- data/lib/omnizip/formats/iso/volume_descriptor.rb +168 -0
- data/lib/omnizip/formats/iso/writer.rb +543 -0
- data/lib/omnizip/formats/iso.rb +133 -0
- data/lib/omnizip/formats/lzip.rb +161 -0
- data/lib/omnizip/formats/lzma_alone.rb +149 -0
- data/lib/omnizip/formats/msi/cab_extractor.rb +181 -0
- data/lib/omnizip/formats/msi/constants.rb +157 -0
- data/lib/omnizip/formats/msi/directory_resolver.rb +188 -0
- data/lib/omnizip/formats/msi/entry.rb +134 -0
- data/lib/omnizip/formats/msi/reader.rb +301 -0
- data/lib/omnizip/formats/msi/string_pool.rb +246 -0
- data/lib/omnizip/formats/msi/table_parser.rb +244 -0
- data/lib/omnizip/formats/msi.rb +73 -0
- data/lib/omnizip/formats/ole/allocation_table.rb +263 -0
- data/lib/omnizip/formats/ole/constants.rb +61 -0
- data/lib/omnizip/formats/ole/dirent.rb +439 -0
- data/lib/omnizip/formats/ole/header.rb +199 -0
- data/lib/omnizip/formats/ole/ranges_io.rb +347 -0
- data/lib/omnizip/formats/ole/storage.rb +482 -0
- data/lib/omnizip/formats/ole/types/variant.rb +338 -0
- data/lib/omnizip/formats/ole.rb +143 -0
- data/lib/omnizip/formats/rar/archive_repairer.rb +240 -0
- data/lib/omnizip/formats/rar/archive_verifier.rb +192 -0
- data/lib/omnizip/formats/rar/block_parser.rb +282 -0
- data/lib/omnizip/formats/rar/compression/bit_stream.rb +180 -0
- data/lib/omnizip/formats/rar/compression/dispatcher.rb +210 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/decoder.rb +212 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/encoder.rb +154 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_builder.rb +217 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_coder.rb +189 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/match_finder.rb +135 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/sliding_window.rb +165 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman.rb +25 -0
- data/lib/omnizip/formats/rar/compression/ppmd/context.rb +103 -0
- data/lib/omnizip/formats/rar/compression/ppmd/decoder.rb +238 -0
- data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +250 -0
- data/lib/omnizip/formats/rar/compression/ppmd.rb +16 -0
- data/lib/omnizip/formats/rar/compression.rb +17 -0
- data/lib/omnizip/formats/rar/compression_method_registry.rb +106 -0
- data/lib/omnizip/formats/rar/constants.rb +88 -0
- data/lib/omnizip/formats/rar/decompressor.rb +316 -0
- data/lib/omnizip/formats/rar/external_writer.rb +311 -0
- data/lib/omnizip/formats/rar/header.rb +209 -0
- data/lib/omnizip/formats/rar/license_validator.rb +111 -0
- data/lib/omnizip/formats/rar/models/rar_archive.rb +77 -0
- data/lib/omnizip/formats/rar/models/rar_entry.rb +65 -0
- data/lib/omnizip/formats/rar/models/rar_volume.rb +56 -0
- data/lib/omnizip/formats/rar/models.rb +14 -0
- data/lib/omnizip/formats/rar/parity_handler.rb +299 -0
- data/lib/omnizip/formats/rar/rar5/compression/lzma.rb +200 -0
- data/lib/omnizip/formats/rar/rar5/compression/lzss.rb +584 -0
- data/lib/omnizip/formats/rar/rar5/compression/store.rb +60 -0
- data/lib/omnizip/formats/rar/rar5/crc32.rb +39 -0
- data/lib/omnizip/formats/rar/rar5/encryption/aes256_cbc.rb +96 -0
- data/lib/omnizip/formats/rar/rar5/encryption/encryption_header.rb +114 -0
- data/lib/omnizip/formats/rar/rar5/encryption/encryption_manager.rb +162 -0
- data/lib/omnizip/formats/rar/rar5/encryption/key_derivation.rb +97 -0
- data/lib/omnizip/formats/rar/rar5/header.rb +208 -0
- data/lib/omnizip/formats/rar/rar5/models/encryption_options.rb +74 -0
- data/lib/omnizip/formats/rar/rar5/models/recovery_options.rb +63 -0
- data/lib/omnizip/formats/rar/rar5/models/solid_options.rb +63 -0
- data/lib/omnizip/formats/rar/rar5/models/volume_options.rb +74 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/ARCHITECTURE.md +290 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_manager.rb +260 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_splitter.rb +155 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb +176 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_encoder.rb +108 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_manager.rb +139 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_stream.rb +121 -0
- data/lib/omnizip/formats/rar/rar5/vint.rb +53 -0
- data/lib/omnizip/formats/rar/rar5/writer.rb +540 -0
- data/lib/omnizip/formats/rar/rar_format_base.rb +239 -0
- data/lib/omnizip/formats/rar/reader.rb +377 -0
- data/lib/omnizip/formats/rar/recovery_record.rb +245 -0
- data/lib/omnizip/formats/rar/volume_manager.rb +166 -0
- data/lib/omnizip/formats/rar/writer.rb +437 -0
- data/lib/omnizip/formats/rar.rb +193 -0
- data/lib/omnizip/formats/rar3/compressor.rb +71 -0
- data/lib/omnizip/formats/rar3/decompressor.rb +64 -0
- data/lib/omnizip/formats/rar3/reader.rb +107 -0
- data/lib/omnizip/formats/rar3/writer.rb +220 -0
- data/lib/omnizip/formats/rar3.rb +15 -0
- data/lib/omnizip/formats/rar5/compressor.rb +71 -0
- data/lib/omnizip/formats/rar5/decompressor.rb +64 -0
- data/lib/omnizip/formats/rar5/reader.rb +130 -0
- data/lib/omnizip/formats/rar5/writer.rb +65 -0
- data/lib/omnizip/formats/rar5.rb +15 -0
- data/lib/omnizip/formats/rpm/constants.rb +58 -0
- data/lib/omnizip/formats/rpm/entry.rb +106 -0
- data/lib/omnizip/formats/rpm/header.rb +106 -0
- data/lib/omnizip/formats/rpm/lead.rb +132 -0
- data/lib/omnizip/formats/rpm/tag.rb +228 -0
- data/lib/omnizip/formats/rpm/writer.rb +652 -0
- data/lib/omnizip/formats/rpm.rb +458 -0
- data/lib/omnizip/formats/seven_zip/bcj2_stream_decompressor.rb +274 -0
- data/lib/omnizip/formats/seven_zip/coder_chain.rb +169 -0
- data/lib/omnizip/formats/seven_zip/constants.rb +126 -0
- data/lib/omnizip/formats/seven_zip/encoded_header.rb +110 -0
- data/lib/omnizip/formats/seven_zip/encrypted_header.rb +139 -0
- data/lib/omnizip/formats/seven_zip/file_collector.rb +143 -0
- data/lib/omnizip/formats/seven_zip/header.rb +102 -0
- data/lib/omnizip/formats/seven_zip/header_encryptor.rb +132 -0
- data/lib/omnizip/formats/seven_zip/header_writer.rb +425 -0
- data/lib/omnizip/formats/seven_zip/models/coder_info.rb +30 -0
- data/lib/omnizip/formats/seven_zip/models/file_entry.rb +65 -0
- data/lib/omnizip/formats/seven_zip/models/folder.rb +67 -0
- data/lib/omnizip/formats/seven_zip/models/stream_info.rb +42 -0
- data/lib/omnizip/formats/seven_zip/models.rb +20 -0
- data/lib/omnizip/formats/seven_zip/parser.rb +671 -0
- data/lib/omnizip/formats/seven_zip/reader.rb +626 -0
- data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +611 -0
- data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +308 -0
- data/lib/omnizip/formats/seven_zip/stream_compressor.rb +151 -0
- data/lib/omnizip/formats/seven_zip/stream_decompressor.rb +166 -0
- data/lib/omnizip/formats/seven_zip/writer.rb +801 -0
- data/lib/omnizip/formats/seven_zip.rb +179 -0
- data/lib/omnizip/formats/tar/constants.rb +73 -0
- data/lib/omnizip/formats/tar/entry.rb +98 -0
- data/lib/omnizip/formats/tar/header.rb +206 -0
- data/lib/omnizip/formats/tar/reader.rb +119 -0
- data/lib/omnizip/formats/tar/writer.rb +212 -0
- data/lib/omnizip/formats/tar.rb +74 -0
- data/lib/omnizip/formats/xar/constants.rb +119 -0
- data/lib/omnizip/formats/xar/entry.rb +268 -0
- data/lib/omnizip/formats/xar/header.rb +223 -0
- data/lib/omnizip/formats/xar/reader.rb +400 -0
- data/lib/omnizip/formats/xar/toc.rb +570 -0
- data/lib/omnizip/formats/xar/writer.rb +461 -0
- data/lib/omnizip/formats/xar.rb +145 -0
- data/lib/omnizip/formats/xz/reader.rb +121 -0
- data/lib/omnizip/formats/xz/writer.rb +416 -0
- data/lib/omnizip/formats/xz.rb +210 -0
- data/lib/omnizip/formats/xz_const.rb +49 -0
- data/lib/omnizip/formats/xz_impl/block_decoder.rb +761 -0
- data/lib/omnizip/formats/xz_impl/block_encoder.rb +304 -0
- data/lib/omnizip/formats/xz_impl/block_header.rb +210 -0
- data/lib/omnizip/formats/xz_impl/block_header_parser.rb +182 -0
- data/lib/omnizip/formats/xz_impl/index_decoder.rb +174 -0
- data/lib/omnizip/formats/xz_impl/index_encoder.rb +120 -0
- data/lib/omnizip/formats/xz_impl/stream_decoder.rb +470 -0
- data/lib/omnizip/formats/xz_impl/stream_encoder.rb +95 -0
- data/lib/omnizip/formats/xz_impl/stream_footer.rb +79 -0
- data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +115 -0
- data/lib/omnizip/formats/xz_impl/stream_header.rb +53 -0
- data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +106 -0
- data/lib/omnizip/formats/xz_impl/vli.rb +128 -0
- data/lib/omnizip/formats/xz_impl.rb +52 -0
- data/lib/omnizip/formats/zip/central_directory_header.rb +223 -0
- data/lib/omnizip/formats/zip/constants.rb +69 -0
- data/lib/omnizip/formats/zip/end_of_central_directory.rb +132 -0
- data/lib/omnizip/formats/zip/local_file_header.rb +136 -0
- data/lib/omnizip/formats/zip/reader.rb +376 -0
- data/lib/omnizip/formats/zip/unix_extra_field.rb +153 -0
- data/lib/omnizip/formats/zip/writer.rb +489 -0
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +102 -0
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +64 -0
- data/lib/omnizip/formats/zip/zip64_extra_field.rb +112 -0
- data/lib/omnizip/formats/zip.rb +50 -0
- data/lib/omnizip/formats.rb +29 -0
- data/lib/omnizip/implementations/base/lzma2_decoder_base.rb +75 -0
- data/lib/omnizip/implementations/base/lzma2_encoder_base.rb +128 -0
- data/lib/omnizip/implementations/base/lzma_decoder_base.rb +83 -0
- data/lib/omnizip/implementations/base/lzma_encoder_base.rb +108 -0
- data/lib/omnizip/implementations/base/state_machine_base.rb +182 -0
- data/lib/omnizip/implementations/base.rb +19 -0
- data/lib/omnizip/implementations/rust/archive.rb +93 -0
- data/lib/omnizip/implementations/rust/library.rb +221 -0
- data/lib/omnizip/implementations/rust.rb +26 -0
- data/lib/omnizip/implementations/seven_zip/lzma/decoder.rb +428 -0
- data/lib/omnizip/implementations/seven_zip/lzma/encoder.rb +456 -0
- data/lib/omnizip/implementations/seven_zip/lzma/match_finder.rb +285 -0
- data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +197 -0
- data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +194 -0
- data/lib/omnizip/implementations/seven_zip/lzma/state_machine.rb +139 -0
- data/lib/omnizip/implementations/seven_zip/lzma.rb +21 -0
- data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +56 -0
- data/lib/omnizip/implementations/seven_zip/lzma2.rb +12 -0
- data/lib/omnizip/implementations/seven_zip.rb +11 -0
- data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +547 -0
- data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +748 -0
- data/lib/omnizip/implementations/xz_utils/lzma2.rb +13 -0
- data/lib/omnizip/implementations/xz_utils.rb +10 -0
- data/lib/omnizip/implementations.rb +25 -0
- data/lib/omnizip/io/buffered_input.rb +147 -0
- data/lib/omnizip/io/buffered_output.rb +106 -0
- data/lib/omnizip/io/source.rb +143 -0
- data/lib/omnizip/io/stream_manager.rb +117 -0
- data/lib/omnizip/io.rb +15 -0
- data/lib/omnizip/link_handler/hard_link.rb +79 -0
- data/lib/omnizip/link_handler/symbolic_link.rb +74 -0
- data/lib/omnizip/link_handler.rb +129 -0
- data/lib/omnizip/metadata/archive_metadata.rb +114 -0
- data/lib/omnizip/metadata/entry_metadata.rb +153 -0
- data/lib/omnizip/metadata/metadata_editor.rb +169 -0
- data/lib/omnizip/metadata/metadata_registry.rb +71 -0
- data/lib/omnizip/metadata/metadata_validator.rb +101 -0
- data/lib/omnizip/metadata.rb +58 -0
- data/lib/omnizip/models/.keep +0 -0
- data/lib/omnizip/models/algorithm_metadata.rb +41 -0
- data/lib/omnizip/models/attribute_apply.rb +40 -0
- data/lib/omnizip/models/compression_options.rb +53 -0
- data/lib/omnizip/models/conversion_options.rb +79 -0
- data/lib/omnizip/models/conversion_result.rb +141 -0
- data/lib/omnizip/models/eta_result.rb +45 -0
- data/lib/omnizip/models/extraction_rule.rb +115 -0
- data/lib/omnizip/models/filter_chain.rb +142 -0
- data/lib/omnizip/models/filter_config.rb +148 -0
- data/lib/omnizip/models/match_result.rb +141 -0
- data/lib/omnizip/models/optimization_suggestion.rb +95 -0
- data/lib/omnizip/models/parallel_options.rb +116 -0
- data/lib/omnizip/models/performance_result.rb +85 -0
- data/lib/omnizip/models/profile_report.rb +116 -0
- data/lib/omnizip/models/progress_options.rb +39 -0
- data/lib/omnizip/models/split_options.rb +116 -0
- data/lib/omnizip/optimization_registry.rb +45 -0
- data/lib/omnizip/parallel/engine.rb +52 -0
- data/lib/omnizip/parallel/job_queue.rb +209 -0
- data/lib/omnizip/parallel/job_scheduler.rb +225 -0
- data/lib/omnizip/parallel/parallel_compressor.rb +326 -0
- data/lib/omnizip/parallel/parallel_extractor.rb +238 -0
- data/lib/omnizip/parallel/thread_pool.rb +60 -0
- data/lib/omnizip/parallel/worker_pool.rb +227 -0
- data/lib/omnizip/parallel.rb +156 -0
- data/lib/omnizip/parity/chunked_block_processor.rb +194 -0
- data/lib/omnizip/parity/galois16.rb +145 -0
- data/lib/omnizip/parity/models/creator_packet.rb +71 -0
- data/lib/omnizip/parity/models/file_description_packet.rb +131 -0
- data/lib/omnizip/parity/models/ifsc_packet.rb +111 -0
- data/lib/omnizip/parity/models/main_packet.rb +126 -0
- data/lib/omnizip/parity/models/packet.rb +156 -0
- data/lib/omnizip/parity/models/packet_registry.rb +102 -0
- data/lib/omnizip/parity/models/recovery_slice_packet.rb +76 -0
- data/lib/omnizip/parity/models.rb +27 -0
- data/lib/omnizip/parity/par2_creator.rb +496 -0
- data/lib/omnizip/parity/par2_repairer.rb +409 -0
- data/lib/omnizip/parity/par2_verifier.rb +373 -0
- data/lib/omnizip/parity/par2cmdline_algorithm.rb +108 -0
- data/lib/omnizip/parity/par2cmdline_coefficients.rb +78 -0
- data/lib/omnizip/parity/reed_solomon_decoder.rb +263 -0
- data/lib/omnizip/parity/reed_solomon_encoder.rb +108 -0
- data/lib/omnizip/parity/reed_solomon_matrix.rb +339 -0
- data/lib/omnizip/parity.rb +207 -0
- data/lib/omnizip/password/encryption_registry.rb +26 -0
- data/lib/omnizip/password/encryption_strategy.rb +96 -0
- data/lib/omnizip/password/password_validator.rb +129 -0
- data/lib/omnizip/password/winzip_aes_strategy.rb +190 -0
- data/lib/omnizip/password/zip_crypto_strategy.rb +135 -0
- data/lib/omnizip/password.rb +88 -0
- data/lib/omnizip/pipe/stream_compressor.rb +124 -0
- data/lib/omnizip/pipe/stream_decompressor.rb +173 -0
- data/lib/omnizip/pipe.rb +120 -0
- data/lib/omnizip/platform/ntfs_streams.rb +200 -0
- data/lib/omnizip/platform.rb +189 -0
- data/lib/omnizip/profile/archive_profile.rb +36 -0
- data/lib/omnizip/profile/balanced_profile.rb +31 -0
- data/lib/omnizip/profile/binary_profile.rb +33 -0
- data/lib/omnizip/profile/compression_profile.rb +157 -0
- data/lib/omnizip/profile/custom_profile.rb +155 -0
- data/lib/omnizip/profile/fast_profile.rb +31 -0
- data/lib/omnizip/profile/maximum_profile.rb +31 -0
- data/lib/omnizip/profile/profile_detector.rb +108 -0
- data/lib/omnizip/profile/profile_registry.rb +160 -0
- data/lib/omnizip/profile/text_profile.rb +33 -0
- data/lib/omnizip/profile.rb +261 -0
- data/lib/omnizip/profiler/memory_profiler.rb +66 -0
- data/lib/omnizip/profiler/method_profiler.rb +49 -0
- data/lib/omnizip/profiler/report_generator.rb +158 -0
- data/lib/omnizip/profiler.rb +192 -0
- data/lib/omnizip/progress/callback_reporter.rb +34 -0
- data/lib/omnizip/progress/console_reporter.rb +59 -0
- data/lib/omnizip/progress/log_reporter.rb +89 -0
- data/lib/omnizip/progress/operation_progress.rb +118 -0
- data/lib/omnizip/progress/progress_bar.rb +156 -0
- data/lib/omnizip/progress/progress_reporter.rb +40 -0
- data/lib/omnizip/progress/progress_tracker.rb +215 -0
- data/lib/omnizip/progress/silent_reporter.rb +22 -0
- data/lib/omnizip/progress.rb +131 -0
- data/lib/omnizip/registry.rb +111 -0
- data/lib/omnizip/rubyzip_compat.rb +61 -0
- data/lib/omnizip/temp/safe_extract.rb +124 -0
- data/lib/omnizip/temp/temp_file.rb +123 -0
- data/lib/omnizip/temp/temp_file_pool.rb +109 -0
- data/lib/omnizip/temp.rb +184 -0
- data/lib/omnizip/version.rb +5 -0
- data/lib/omnizip/zip/entry.rb +160 -0
- data/lib/omnizip/zip/file.rb +485 -0
- data/lib/omnizip/zip/input_stream.rb +270 -0
- data/lib/omnizip/zip/output_stream.rb +320 -0
- data/lib/omnizip/zip.rb +23 -0
- data/lib/omnizip.rb +157 -0
- data/lib/tasks/msi_test_files.rake +66 -0
- data/lib/tasks/platform_gems.rake +147 -0
- data/lib/tasks/rust_backend.rake +48 -0
- data/readme-docs/advanced-features.adoc +514 -0
- data/readme-docs/api-usage.adoc +445 -0
- data/readme-docs/architecture.adoc +450 -0
- data/readme-docs/archive-formats.adoc +479 -0
- data/readme-docs/cli-usage.adoc +222 -0
- data/readme-docs/compression-algorithms.adoc +446 -0
- data/readme-docs/compression-profiles.adoc +247 -0
- data/readme-docs/encryption-checksums.adoc +328 -0
- data/readme-docs/format-converter.adoc +316 -0
- data/readme-docs/installation.adoc +228 -0
- data/readme-docs/par2-archives.adoc +608 -0
- data/readme-docs/performance-profiler.adoc +389 -0
- data/readme-docs/preprocessing-filters.adoc +280 -0
- data/vendor/libomnizip_ffi.so +0 -0
- data/xz-file-format-1.2.1.txt +1174 -0
- metadata +768 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Parallel
|
|
7
|
+
# Parallel extraction coordinator using Fractor
|
|
8
|
+
#
|
|
9
|
+
# Manages parallel extraction of files from an archive.
|
|
10
|
+
# Distributes extraction work across multiple workers and
|
|
11
|
+
# writes files to disk in a thread-safe manner.
|
|
12
|
+
#
|
|
13
|
+
# @example Extract archive in parallel
|
|
14
|
+
# extractor = Omnizip::Parallel::ParallelExtractor.new(threads: 4)
|
|
15
|
+
# extractor.extract('backup.zip', 'output/')
|
|
16
|
+
#
|
|
17
|
+
# @example With options
|
|
18
|
+
# options = Omnizip::Models::ParallelOptions.new
|
|
19
|
+
# options.threads = 8
|
|
20
|
+
# extractor = Omnizip::Parallel::ParallelExtractor.new(options)
|
|
21
|
+
# extractor.extract('backup.zip', 'output/')
|
|
22
|
+
class ParallelExtractor
|
|
23
|
+
# @return [Omnizip::Models::ParallelOptions] parallel options
|
|
24
|
+
attr_reader :options
|
|
25
|
+
|
|
26
|
+
# @return [Hash] extraction statistics
|
|
27
|
+
attr_reader :stats
|
|
28
|
+
|
|
29
|
+
# Initialize parallel extractor
|
|
30
|
+
#
|
|
31
|
+
# @param options [Omnizip::Models::ParallelOptions, Hash] parallel options
|
|
32
|
+
# @param threads [Integer] number of threads (overrides options)
|
|
33
|
+
def initialize(options = nil, threads: nil)
|
|
34
|
+
@options = case options
|
|
35
|
+
when Omnizip::Models::ParallelOptions
|
|
36
|
+
options.dup
|
|
37
|
+
when Hash
|
|
38
|
+
Omnizip::Models::ParallelOptions.new.apply(options)
|
|
39
|
+
else
|
|
40
|
+
Omnizip::Models::ParallelOptions.new
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
@options.threads = threads if threads
|
|
44
|
+
@options.validate_options!
|
|
45
|
+
|
|
46
|
+
@stats = {
|
|
47
|
+
files_extracted: 0,
|
|
48
|
+
bytes_extracted: 0,
|
|
49
|
+
start_time: nil,
|
|
50
|
+
end_time: nil,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@write_mutex = Mutex.new
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Extract archive to directory in parallel
|
|
57
|
+
#
|
|
58
|
+
# @param archive [String] archive path
|
|
59
|
+
# @param dest [String] destination directory
|
|
60
|
+
# @param options [Hash] extraction options
|
|
61
|
+
# @option options [Boolean] :overwrite overwrite existing files
|
|
62
|
+
# @option options [Proc] :progress progress callback
|
|
63
|
+
# @return [Array<String>] extracted file paths
|
|
64
|
+
def extract(archive, dest, **options)
|
|
65
|
+
unless ::File.exist?(archive)
|
|
66
|
+
raise Errno::ENOENT,
|
|
67
|
+
"Archive not found: #{archive}"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
overwrite = options.fetch(:overwrite, false)
|
|
71
|
+
options[:progress]
|
|
72
|
+
|
|
73
|
+
@stats[:start_time] = Time.now
|
|
74
|
+
|
|
75
|
+
# Read archive to get entries
|
|
76
|
+
entries = read_archive_entries(archive)
|
|
77
|
+
|
|
78
|
+
# Create destination directory
|
|
79
|
+
FileUtils.mkdir_p(dest)
|
|
80
|
+
|
|
81
|
+
# Create job queue
|
|
82
|
+
job_queue = JobQueue.new(max_size: @options.queue_size)
|
|
83
|
+
|
|
84
|
+
# Schedule jobs
|
|
85
|
+
entries.each do |entry|
|
|
86
|
+
job_queue.push_with_size(
|
|
87
|
+
file: entry.filename,
|
|
88
|
+
size: safe_entry_size(entry),
|
|
89
|
+
data: { entry_name: entry.filename },
|
|
90
|
+
)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Create work items from jobs, largest first
|
|
94
|
+
work_items = []
|
|
95
|
+
until job_queue.empty?
|
|
96
|
+
job = job_queue.pop(timeout: 0.1)
|
|
97
|
+
break unless job
|
|
98
|
+
|
|
99
|
+
work_items << job.data[:entry_name]
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Threads, not Ractors: Omnizip's autoloads and Proc-holding
|
|
103
|
+
# codec constants cannot cross Ractor boundaries on Ruby <= 3.3
|
|
104
|
+
pool = ThreadPool.new(size: @options.threads)
|
|
105
|
+
raw_results, raw_errors = pool.map(work_items) do |entry_name|
|
|
106
|
+
process_entry(archive, dest, entry_name)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Handle errors (raw_errors holds nil for every item that
|
|
110
|
+
# succeeded — zip+compact would keep those pairs)
|
|
111
|
+
failure_pairs = raw_errors.each_with_index.filter_map do |error, index|
|
|
112
|
+
[work_items[index], error] if error
|
|
113
|
+
end
|
|
114
|
+
unless failure_pairs.empty?
|
|
115
|
+
error_msgs = failure_pairs.map { |name, e| "#{name}: #{e.message}" }
|
|
116
|
+
.join("\n")
|
|
117
|
+
raise Omnizip::DecompressionError, "Extraction errors:\n#{error_msgs}"
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
results = raw_results
|
|
121
|
+
|
|
122
|
+
# Write files to disk (thread-safe)
|
|
123
|
+
extracted_paths = write_extracted_files(results, overwrite: overwrite)
|
|
124
|
+
|
|
125
|
+
@stats[:end_time] = Time.now
|
|
126
|
+
@stats[:files_extracted] = results.size
|
|
127
|
+
|
|
128
|
+
extracted_paths
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Get extraction statistics
|
|
132
|
+
#
|
|
133
|
+
# @return [Hash] statistics
|
|
134
|
+
def statistics
|
|
135
|
+
duration = if @stats[:start_time] && @stats[:end_time]
|
|
136
|
+
@stats[:end_time] - @stats[:start_time]
|
|
137
|
+
else
|
|
138
|
+
0
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
@stats.merge(
|
|
142
|
+
duration: duration,
|
|
143
|
+
throughput_mbps: calculate_throughput(duration),
|
|
144
|
+
)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
private
|
|
148
|
+
|
|
149
|
+
# Decompress one entry in a worker thread. Each worker opens
|
|
150
|
+
# the archive independently — its own file handle per thread.
|
|
151
|
+
def process_entry(archive_path, dest_dir, entry_name)
|
|
152
|
+
entry = Omnizip::Formats::Zip::Reader.new(archive_path)
|
|
153
|
+
.entries.find { |e| e.filename == entry_name }
|
|
154
|
+
raise Errno::ENOENT, "Entry not found: #{entry_name}" unless entry
|
|
155
|
+
|
|
156
|
+
{
|
|
157
|
+
entry_name: entry_name,
|
|
158
|
+
dest_path: ::File.join(dest_dir, entry_name),
|
|
159
|
+
data: entry.directory? ? "" : read_entry_data(archive_path, entry_name),
|
|
160
|
+
directory: entry.directory?,
|
|
161
|
+
unix_perms: entry.unix_permissions.to_i,
|
|
162
|
+
}
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def read_entry_data(archive_path, entry_name)
|
|
166
|
+
Omnizip::Formats::Zip::Reader.new(archive_path)
|
|
167
|
+
.read_entry(entry_name)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def safe_entry_size(entry)
|
|
171
|
+
entry.uncompressed_size.to_i
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Read archive entries through the native reader
|
|
175
|
+
#
|
|
176
|
+
# @param archive_path [String] archive path
|
|
177
|
+
# @return [Array<CentralDirectoryHeader>] array of entries
|
|
178
|
+
def read_archive_entries(archive_path)
|
|
179
|
+
Omnizip::Formats::Zip::Reader.new(archive_path).entries
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Write extracted files to disk
|
|
183
|
+
#
|
|
184
|
+
# @param results [Array] extraction results
|
|
185
|
+
# @param overwrite [Boolean] overwrite existing files
|
|
186
|
+
# @return [Array<String>] extracted file paths
|
|
187
|
+
def write_extracted_files(results, overwrite: false)
|
|
188
|
+
extracted_paths = []
|
|
189
|
+
|
|
190
|
+
results.each do |result|
|
|
191
|
+
next unless result
|
|
192
|
+
|
|
193
|
+
dest_path = result[:dest_path]
|
|
194
|
+
|
|
195
|
+
# Thread-safe file writing
|
|
196
|
+
@write_mutex.synchronize do
|
|
197
|
+
if result[:directory]
|
|
198
|
+
# mkdir_p is idempotent — a file entry may already have
|
|
199
|
+
# created this directory as its parent
|
|
200
|
+
FileUtils.mkdir_p(dest_path)
|
|
201
|
+
extracted_paths << dest_path
|
|
202
|
+
next
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Check if file exists
|
|
206
|
+
if ::File.exist?(dest_path) && !overwrite
|
|
207
|
+
raise Errno::EEXIST, "File exists: #{dest_path}"
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
FileUtils.mkdir_p(::File.dirname(dest_path))
|
|
211
|
+
::File.binwrite(dest_path, result[:data])
|
|
212
|
+
|
|
213
|
+
# Set permissions if Unix
|
|
214
|
+
if result[:unix_perms].positive?
|
|
215
|
+
::File.chmod(result[:unix_perms] & 0o777, dest_path)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
@stats[:bytes_extracted] += result[:data].bytesize
|
|
219
|
+
|
|
220
|
+
extracted_paths << dest_path
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
extracted_paths
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Calculate throughput in MB/s
|
|
228
|
+
#
|
|
229
|
+
# @param duration [Float] duration in seconds
|
|
230
|
+
# @return [Float] throughput in MB/s
|
|
231
|
+
def calculate_throughput(duration)
|
|
232
|
+
return 0.0 if duration.zero?
|
|
233
|
+
|
|
234
|
+
(@stats[:bytes_extracted].to_f / (1024 * 1024)) / duration
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Parallel
|
|
5
|
+
# Bounded thread pool for library work.
|
|
6
|
+
#
|
|
7
|
+
# Unlike the Fractor pool, threads share the VM state — Ractor
|
|
8
|
+
# workers cannot trigger Omnizip's autoloads or touch Proc-holding
|
|
9
|
+
# codec constants on Ruby <= 3.3 ("require by autoload on
|
|
10
|
+
# non-main Ractor is not supported"). Decompression itself still
|
|
11
|
+
# parallelizes: the zlib/bzip2 C extensions release the GVL.
|
|
12
|
+
class ThreadPool
|
|
13
|
+
# @return [Integer] number of worker threads
|
|
14
|
+
attr_reader :size
|
|
15
|
+
|
|
16
|
+
# Initialize the pool
|
|
17
|
+
#
|
|
18
|
+
# @param size [Integer] worker thread count (at least 1)
|
|
19
|
+
def initialize(size:)
|
|
20
|
+
@size = [size.to_i, 1].max
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Run +block+ for every item, at most +size+ at a time, and
|
|
24
|
+
# return a pair of parallel arrays: results (nil where an item
|
|
25
|
+
# raised) and errors (nil where it succeeded). Item order is
|
|
26
|
+
# preserved in both arrays.
|
|
27
|
+
#
|
|
28
|
+
# @param items [Array] work items
|
|
29
|
+
# @yieldparam item [Object] one work item
|
|
30
|
+
# @return [Array<Array, Array>]
|
|
31
|
+
def map(items)
|
|
32
|
+
results = Array.new(items.size)
|
|
33
|
+
errors = Array.new(items.size)
|
|
34
|
+
queue = Queue.new
|
|
35
|
+
items.each_with_index { |item, index| queue << [item, index] }
|
|
36
|
+
|
|
37
|
+
threads = Array.new(@size) do
|
|
38
|
+
Thread.new do
|
|
39
|
+
loop do
|
|
40
|
+
begin
|
|
41
|
+
item, index = queue.pop(true)
|
|
42
|
+
rescue ThreadError
|
|
43
|
+
break
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
begin
|
|
47
|
+
results[index] = yield(item)
|
|
48
|
+
rescue StandardError => e
|
|
49
|
+
errors[index] = e
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
threads.each(&:join)
|
|
55
|
+
|
|
56
|
+
[results, errors]
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fractor"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Parallel
|
|
7
|
+
# Worker pool wrapper for Fractor-based parallel processing
|
|
8
|
+
#
|
|
9
|
+
# Manages a pool of Fractor workers for parallel compression/extraction.
|
|
10
|
+
# Handles job distribution, result collection, and graceful shutdown.
|
|
11
|
+
#
|
|
12
|
+
# @example Create and use worker pool
|
|
13
|
+
# pool = Omnizip::Parallel::WorkerPool.new(
|
|
14
|
+
# worker_class: CompressionWorker,
|
|
15
|
+
# num_workers: 4
|
|
16
|
+
# )
|
|
17
|
+
# pool.start
|
|
18
|
+
# pool.submit(work_item)
|
|
19
|
+
# results = pool.results
|
|
20
|
+
# pool.shutdown
|
|
21
|
+
class WorkerPool
|
|
22
|
+
# @return [Fractor::Supervisor] underlying Fractor supervisor
|
|
23
|
+
attr_reader :supervisor
|
|
24
|
+
|
|
25
|
+
# @return [Array] collected results
|
|
26
|
+
attr_reader :results
|
|
27
|
+
|
|
28
|
+
# @return [Array] collected errors
|
|
29
|
+
attr_reader :errors
|
|
30
|
+
|
|
31
|
+
# @return [Boolean] whether pool is running
|
|
32
|
+
attr_reader :running
|
|
33
|
+
|
|
34
|
+
# Initialize worker pool
|
|
35
|
+
#
|
|
36
|
+
# @param worker_class [Class] Fractor::Worker subclass
|
|
37
|
+
# @param num_workers [Integer] number of worker threads
|
|
38
|
+
# @param continuous [Boolean] continuous mode for long-running tasks
|
|
39
|
+
def initialize(worker_class:, num_workers: nil, continuous: false)
|
|
40
|
+
@worker_class = worker_class
|
|
41
|
+
@num_workers = num_workers || detect_cpu_count
|
|
42
|
+
@continuous = continuous
|
|
43
|
+
@supervisor = nil
|
|
44
|
+
@results = []
|
|
45
|
+
@errors = []
|
|
46
|
+
@running = false
|
|
47
|
+
@result_mutex = Mutex.new
|
|
48
|
+
@work_queue = nil
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Start the worker pool
|
|
52
|
+
#
|
|
53
|
+
# @return [void]
|
|
54
|
+
def start
|
|
55
|
+
return if @running
|
|
56
|
+
|
|
57
|
+
# Create Fractor supervisor with worker pool configuration
|
|
58
|
+
@supervisor = Fractor::Supervisor.new(
|
|
59
|
+
worker_pools: [
|
|
60
|
+
{
|
|
61
|
+
worker_class: @worker_class,
|
|
62
|
+
num_workers: @num_workers,
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
continuous_mode: @continuous,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# For continuous mode, set up work queue
|
|
69
|
+
if @continuous
|
|
70
|
+
@work_queue = Fractor::WorkQueue.new
|
|
71
|
+
@work_queue.register_with_supervisor(@supervisor)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
@running = true
|
|
75
|
+
|
|
76
|
+
# Start supervisor in background thread for continuous mode
|
|
77
|
+
if @continuous
|
|
78
|
+
@supervisor_thread = Thread.new do
|
|
79
|
+
@supervisor.run
|
|
80
|
+
rescue StandardError => e
|
|
81
|
+
@result_mutex.synchronize do
|
|
82
|
+
@errors << { error: e, message: "Supervisor error: #{e.message}" }
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
else
|
|
86
|
+
# For batch mode, don't start yet - wait for work items
|
|
87
|
+
@supervisor.start_workers
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Submit work item to the pool
|
|
92
|
+
#
|
|
93
|
+
# @param work [Fractor::Work] work item to process
|
|
94
|
+
# @return [void]
|
|
95
|
+
def submit(work)
|
|
96
|
+
raise Omnizip::IOError, "Worker pool not started" unless @running
|
|
97
|
+
|
|
98
|
+
if @continuous
|
|
99
|
+
# In continuous mode, add to work queue
|
|
100
|
+
@work_queue << work
|
|
101
|
+
else
|
|
102
|
+
# In batch mode, add to supervisor
|
|
103
|
+
@supervisor.add_work_item(work)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Submit multiple work items
|
|
108
|
+
#
|
|
109
|
+
# @param works [Array<Fractor::Work>] array of work items
|
|
110
|
+
# @return [void]
|
|
111
|
+
def submit_batch(works)
|
|
112
|
+
works.each { |work| submit(work) }
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Run the pool in batch mode and wait for completion
|
|
116
|
+
#
|
|
117
|
+
# @return [void]
|
|
118
|
+
def run
|
|
119
|
+
raise Omnizip::IOError, "Can only run in batch mode" if @continuous
|
|
120
|
+
raise Omnizip::IOError, "Worker pool not started" unless @running
|
|
121
|
+
|
|
122
|
+
@supervisor.run
|
|
123
|
+
|
|
124
|
+
# Collect results
|
|
125
|
+
collect_results
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Shutdown the worker pool
|
|
129
|
+
#
|
|
130
|
+
# @param timeout [Numeric] timeout in seconds
|
|
131
|
+
# @return [void]
|
|
132
|
+
def shutdown(timeout: 30)
|
|
133
|
+
return unless @running
|
|
134
|
+
|
|
135
|
+
# Stop in BOTH modes: batch worker Ractors otherwise linger
|
|
136
|
+
# in Ractor.receive for the life of the process, burning CPU
|
|
137
|
+
# after the batch completes
|
|
138
|
+
@supervisor&.stop
|
|
139
|
+
|
|
140
|
+
if @continuous
|
|
141
|
+
@supervisor_thread&.join(timeout)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Collect final results
|
|
145
|
+
collect_results
|
|
146
|
+
|
|
147
|
+
@running = false
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Get successful results
|
|
151
|
+
#
|
|
152
|
+
# @return [Array] array of successful results
|
|
153
|
+
def successful_results
|
|
154
|
+
@result_mutex.synchronize { @results.dup }
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Get failed results
|
|
158
|
+
#
|
|
159
|
+
# @return [Array] array of errors
|
|
160
|
+
def failed_results
|
|
161
|
+
@result_mutex.synchronize { @errors.dup }
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Get pool statistics
|
|
165
|
+
#
|
|
166
|
+
# @return [Hash] statistics hash
|
|
167
|
+
def stats
|
|
168
|
+
return {} unless @supervisor
|
|
169
|
+
|
|
170
|
+
{
|
|
171
|
+
workers: @num_workers,
|
|
172
|
+
running: @running,
|
|
173
|
+
continuous: @continuous,
|
|
174
|
+
results: @results.size,
|
|
175
|
+
errors: @errors.size,
|
|
176
|
+
total_processed: @results.size + @errors.size,
|
|
177
|
+
}
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Check if pool has completed all work
|
|
181
|
+
#
|
|
182
|
+
# @return [Boolean] true if complete
|
|
183
|
+
def complete?
|
|
184
|
+
return false if @continuous
|
|
185
|
+
return false unless @supervisor
|
|
186
|
+
|
|
187
|
+
# In batch mode, check if all work is processed
|
|
188
|
+
result_aggregator = @supervisor.results
|
|
189
|
+
result_aggregator && !@supervisor.work_queue.empty?
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
private
|
|
193
|
+
|
|
194
|
+
# Collect results from supervisor
|
|
195
|
+
#
|
|
196
|
+
# @return [void]
|
|
197
|
+
def collect_results
|
|
198
|
+
return unless @supervisor
|
|
199
|
+
|
|
200
|
+
result_aggregator = @supervisor.results
|
|
201
|
+
return unless result_aggregator
|
|
202
|
+
|
|
203
|
+
@result_mutex.synchronize do
|
|
204
|
+
# Collect successful results
|
|
205
|
+
result_aggregator.results.each do |work_result|
|
|
206
|
+
@results << work_result
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Collect errors
|
|
210
|
+
result_aggregator.errors.each do |error_result|
|
|
211
|
+
@errors << error_result
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# Detect number of available CPU cores
|
|
217
|
+
#
|
|
218
|
+
# @return [Integer] number of CPUs
|
|
219
|
+
def detect_cpu_count
|
|
220
|
+
require "etc"
|
|
221
|
+
Etc.nprocessors
|
|
222
|
+
rescue StandardError
|
|
223
|
+
4 # fallback
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
# Parallel processing module for multi-threaded compression/extraction
|
|
5
|
+
#
|
|
6
|
+
# Leverages Fractor for parallel processing to utilize multi-core CPUs.
|
|
7
|
+
# Provides high-level APIs for parallel compression and extraction operations.
|
|
8
|
+
#
|
|
9
|
+
# @example Auto-detect CPU count and compress in parallel
|
|
10
|
+
# Omnizip::Parallel.compress_directory('files/', 'backup.zip')
|
|
11
|
+
#
|
|
12
|
+
# @example Custom thread count
|
|
13
|
+
# Omnizip::Parallel.compress_directory('files/', 'backup.zip', threads: 8)
|
|
14
|
+
#
|
|
15
|
+
# @example Parallel extraction
|
|
16
|
+
# Omnizip::Parallel.extract_archive('large.zip', 'output/', threads: 4)
|
|
17
|
+
#
|
|
18
|
+
# @example Configure globally
|
|
19
|
+
# Omnizip::Parallel.configure do |config|
|
|
20
|
+
# config.default_threads = 8
|
|
21
|
+
# config.queue_size = 100
|
|
22
|
+
# config.load_balancing = :dynamic
|
|
23
|
+
# end
|
|
24
|
+
module Parallel
|
|
25
|
+
# Nested classes - autoloaded
|
|
26
|
+
autoload :JobQueue, "omnizip/parallel/job_queue"
|
|
27
|
+
autoload :JobScheduler, "omnizip/parallel/job_scheduler"
|
|
28
|
+
autoload :WorkerPool, "omnizip/parallel/worker_pool"
|
|
29
|
+
autoload :Engine, "omnizip/parallel/engine"
|
|
30
|
+
autoload :ParallelCompressor, "omnizip/parallel/parallel_compressor"
|
|
31
|
+
autoload :ParallelExtractor, "omnizip/parallel/parallel_extractor"
|
|
32
|
+
autoload :ThreadPool, "omnizip/parallel/thread_pool"
|
|
33
|
+
|
|
34
|
+
class << self
|
|
35
|
+
# Global configuration
|
|
36
|
+
attr_accessor :config
|
|
37
|
+
|
|
38
|
+
# Configure parallel processing globally
|
|
39
|
+
#
|
|
40
|
+
# @yield [config] Configuration block
|
|
41
|
+
# @yieldparam config [Omnizip::Models::ParallelOptions] configuration object
|
|
42
|
+
# @return [void]
|
|
43
|
+
#
|
|
44
|
+
# @example
|
|
45
|
+
# Omnizip::Parallel.configure do |config|
|
|
46
|
+
# config.threads = 8
|
|
47
|
+
# config.queue_size = 100
|
|
48
|
+
# config.strategy = :dynamic
|
|
49
|
+
# end
|
|
50
|
+
def configure
|
|
51
|
+
@config ||= Omnizip::Models::ParallelOptions.new
|
|
52
|
+
yield @config if block_given?
|
|
53
|
+
@config.validate_options!
|
|
54
|
+
@config
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Compress directory in parallel
|
|
58
|
+
#
|
|
59
|
+
# @param dir [String] directory path
|
|
60
|
+
# @param output [String] output archive path
|
|
61
|
+
# @param options [Hash] compression options
|
|
62
|
+
# @option options [Integer] :threads number of threads
|
|
63
|
+
# @option options [Symbol] :compression compression method
|
|
64
|
+
# @option options [Integer] :level compression level
|
|
65
|
+
# @option options [Boolean] :recursive include subdirectories
|
|
66
|
+
# @option options [Proc] :progress progress callback
|
|
67
|
+
# @return [String] path to created archive
|
|
68
|
+
#
|
|
69
|
+
# @example
|
|
70
|
+
# Omnizip::Parallel.compress_directory('files/', 'backup.zip')
|
|
71
|
+
# Omnizip::Parallel.compress_directory('files/', 'backup.zip', threads: 8)
|
|
72
|
+
def compress_directory(dir, output, **options)
|
|
73
|
+
threads = options.delete(:threads) || @config&.threads
|
|
74
|
+
|
|
75
|
+
compressor = ParallelCompressor.new(@config, threads: threads)
|
|
76
|
+
result = compressor.compress(dir, output, **options)
|
|
77
|
+
|
|
78
|
+
# Print stats if verbose
|
|
79
|
+
if options[:verbose] || @config&.verbose
|
|
80
|
+
stats = compressor.statistics
|
|
81
|
+
print_stats("Compression", stats)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
result
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Extract archive in parallel
|
|
88
|
+
#
|
|
89
|
+
# @param archive [String] archive path
|
|
90
|
+
# @param dest [String] destination directory
|
|
91
|
+
# @param options [Hash] extraction options
|
|
92
|
+
# @option options [Integer] :threads number of threads
|
|
93
|
+
# @option options [Boolean] :overwrite overwrite existing files
|
|
94
|
+
# @option options [Proc] :progress progress callback
|
|
95
|
+
# @return [Array<String>] extracted file paths
|
|
96
|
+
#
|
|
97
|
+
# @example
|
|
98
|
+
# Omnizip::Parallel.extract_archive('large.zip', 'output/')
|
|
99
|
+
# Omnizip::Parallel.extract_archive('large.zip', 'output/', threads: 4)
|
|
100
|
+
def extract_archive(archive, dest, **options)
|
|
101
|
+
threads = options.delete(:threads) || @config&.threads
|
|
102
|
+
|
|
103
|
+
extractor = ParallelExtractor.new(@config, threads: threads)
|
|
104
|
+
result = extractor.extract(archive, dest, **options)
|
|
105
|
+
|
|
106
|
+
# Print stats if verbose
|
|
107
|
+
if options[:verbose] || @config&.verbose
|
|
108
|
+
stats = extractor.statistics
|
|
109
|
+
print_stats("Extraction", stats)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
result
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Get default configuration
|
|
116
|
+
#
|
|
117
|
+
# @return [Omnizip::Models::ParallelOptions] configuration
|
|
118
|
+
def default_config
|
|
119
|
+
@default_config ||= Omnizip::Models::ParallelOptions.new
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Reset configuration to defaults
|
|
123
|
+
#
|
|
124
|
+
# @return [void]
|
|
125
|
+
def reset_config
|
|
126
|
+
@config = Omnizip::Models::ParallelOptions.new
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
private
|
|
130
|
+
|
|
131
|
+
# Print statistics
|
|
132
|
+
#
|
|
133
|
+
# @param operation [String] operation name
|
|
134
|
+
# @param stats [Hash] statistics hash
|
|
135
|
+
def print_stats(operation, stats)
|
|
136
|
+
puts "\n=== #{operation} Statistics ==="
|
|
137
|
+
puts "Files processed: #{stats[:files_processed] || stats[:files_extracted] || 0}"
|
|
138
|
+
puts "Duration: #{'%.2f' % stats[:duration]}s"
|
|
139
|
+
puts "Throughput: #{'%.2f' % stats[:throughput_mbps]} MB/s"
|
|
140
|
+
|
|
141
|
+
if stats[:compression_ratio]
|
|
142
|
+
puts "Compression ratio: #{'%.2f' % stats[:compression_ratio]}%"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
puts "================================\n"
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Initialize default configuration
|
|
150
|
+
def self.setup_default_config
|
|
151
|
+
@config = Omnizip::Models::ParallelOptions.new
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
setup_default_config
|
|
155
|
+
end
|
|
156
|
+
end
|