unpack_strategy: add zstd
This commit is contained in:
		
							parent
							
								
									109f24fd60
								
							
						
					
					
						commit
						fe9a039774
					
				@ -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)
 | 
			
		||||
 | 
			
		||||
@ -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.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								Library/Homebrew/test/support/fixtures/cask/container.tar.zst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Library/Homebrew/test/support/fixtures/cask/container.tar.zst
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										10
									
								
								Library/Homebrew/test/unpack_strategy/zstd_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Library/Homebrew/test/unpack_strategy/zstd_spec.rb
									
									
									
									
									
										Normal 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
 | 
			
		||||
@ -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"
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										38
									
								
								Library/Homebrew/unpack_strategy/zstd.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								Library/Homebrew/unpack_strategy/zstd.rb
									
									
									
									
									
										Normal 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
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user