unpack_strategy: add zstd

This commit is contained in:
Alexander Bayandin 2021-09-16 15:56:31 +01:00
parent 109f24fd60
commit fe9a039774
No known key found for this signature in database
GPG Key ID: 444BD9CA93262701
7 changed files with 74 additions and 10 deletions

View File

@ -81,6 +81,10 @@ class DependencyCollector
Dependency.new("xz", tags) unless which("xz")
end
def zstd_dep_if_needed(tags)
Dependency.new("zstd", tags) unless which("zstd")
end
def unzip_dep_if_needed(tags)
Dependency.new("unzip", tags) unless which("unzip")
end
@ -171,6 +175,7 @@ class DependencyCollector
def parse_url_spec(url, tags)
case File.extname(url)
when ".xz" then xz_dep_if_needed(tags)
when ".zst" then zstd_dep_if_needed(tags)
when ".zip" then unzip_dep_if_needed(tags)
when ".bz2" then bzip2_dep_if_needed(tags)
when ".lha", ".lzh" then Dependency.new("lha", tags)

View File

@ -231,7 +231,7 @@ class Pathname
bottle_ext, = HOMEBREW_BOTTLES_EXTNAME_REGEX.match(basename).to_a
return bottle_ext if bottle_ext
archive_ext = basename[/(\.(tar|cpio|pax)\.(gz|bz2|lz|xz|Z))\Z/, 1]
archive_ext = basename[/(\.(tar|cpio|pax)\.(gz|bz2|lz|xz|zst|Z))\Z/, 1]
return archive_ext if archive_ext
# Don't treat version numbers as extname.

View File

@ -0,0 +1,10 @@
# typed: false
# frozen_string_literal: true
require_relative "shared_examples"
describe UnpackStrategy::Zstd do
let(:path) { TEST_FIXTURE_DIR/"cask/container.tar.zst" }
include_examples "UnpackStrategy::detect"
end

View File

@ -44,12 +44,13 @@ module UnpackStrategy
def self.strategies
@strategies ||= [
Tar, # Needs to be before Bzip2/Gzip/Xz/Lzma.
Tar, # Needs to be before Bzip2/Gzip/Xz/Lzma/Zstd.
Pax,
Gzip,
Dmg, # Needs to be before Bzip2/Xz/Lzma.
Lzma,
Xz,
Zstd,
Lzip,
Air, # Needs to be before `Zip`.
Jar, # Needs to be before `Zip`.
@ -203,3 +204,4 @@ require "unpack_strategy/uncompressed"
require "unpack_strategy/xar"
require "unpack_strategy/xz"
require "unpack_strategy/zip"
require "unpack_strategy/zstd"

View File

@ -20,14 +20,15 @@ module UnpackStrategy
".tbz", ".tbz2", ".tar.bz2",
".tgz", ".tar.gz",
".tlzma", ".tar.lzma",
".txz", ".tar.xz"
".txz", ".tar.xz",
".tar.zst"
]
end
def self.can_extract?(path)
return true if path.magic_number.match?(/\A.{257}ustar/n)
return false unless [Bzip2, Gzip, Lzip, Xz].any? { |s| s.can_extract?(path) }
return false unless [Bzip2, Gzip, Lzip, Xz, Zstd].any? { |s| s.can_extract?(path) }
# Check if `tar` can list the contents, then it can also extract it.
stdout, _, status = system_command("tar", args: ["--list", "--file", path], print_stderr: false)
@ -39,12 +40,12 @@ module UnpackStrategy
sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) }
def extract_to_dir(unpack_dir, basename:, verbose:)
Dir.mktmpdir do |tmpdir|
tar_path = path
if DependencyCollector.tar_needs_xz_dependency? && Xz.can_extract?(path)
tmpdir = Pathname(tmpdir)
Xz.new(path).extract(to: tmpdir, verbose: verbose)
tar_path = tmpdir.children.first
tar_path = if DependencyCollector.tar_needs_xz_dependency? && Xz.can_extract?(path)
subextract(Xz, Pathname(tmpdir), verbose)
elsif Zstd.can_extract?(path)
subextract(Zstd, Pathname(tmpdir), verbose)
else
path
end
system_command! "tar",
@ -54,5 +55,13 @@ module UnpackStrategy
verbose: verbose
end
end
sig {
params(extractor: T.any(T.class_of(Xz), T.class_of(Zstd)), dir: Pathname, verbose: T::Boolean).returns(Pathname)
}
def subextract(extractor, dir, verbose)
extractor.new(path).extract(to: dir, verbose: verbose)
T.must(dir.children.first)
end
end
end

View File

@ -0,0 +1,38 @@
# typed: true
# frozen_string_literal: true
module UnpackStrategy
# Strategy for unpacking zstd archives.
class Zstd
extend T::Sig
include UnpackStrategy
using Magic
sig { returns(T::Array[String]) }
def self.extensions
[".zst"]
end
def self.can_extract?(path)
path.magic_number.match?(/\x28\xB5\x2F\xFD/n)
end
def dependencies
@dependencies ||= [Formula["zstd"]]
end
private
sig { override.params(unpack_dir: Pathname, basename: Pathname, verbose: T::Boolean).returns(T.untyped) }
def extract_to_dir(unpack_dir, basename:, verbose:)
FileUtils.cp path, unpack_dir/basename, preserve: true
quiet_flags = verbose ? [] : ["-q"]
system_command! "unzstd",
args: [*quiet_flags, "-T0", "--", unpack_dir/basename],
env: { "PATH" => PATH.new(Formula["zstd"].opt_bin, ENV["PATH"]) },
verbose: verbose
end
end
end