diff --git a/Library/Homebrew/download_strategy.rb b/Library/Homebrew/download_strategy.rb index 7d8465048a..de269d55eb 100644 --- a/Library/Homebrew/download_strategy.rb +++ b/Library/Homebrew/download_strategy.rb @@ -47,8 +47,11 @@ class AbstractDownloadStrategy # chdir into the newly-unpacked directory. # Unlike {Resource#stage}, this does not take a block. def stage - UnpackStrategy.detect(cached_location, ref_type: @ref_type, ref: @ref) + UnpackStrategy.detect(cached_location, + extension_only: true, + ref_type: @ref_type, ref: @ref) .extract_nestedly(basename: basename_without_params, + extension_only: true, verbose: ARGV.verbose? && !shutup) end diff --git a/Library/Homebrew/unpack_strategy.rb b/Library/Homebrew/unpack_strategy.rb index 154724ec0a..d4068963f3 100644 --- a/Library/Homebrew/unpack_strategy.rb +++ b/Library/Homebrew/unpack_strategy.rb @@ -1,36 +1,60 @@ module UnpackStrategy - # length of the longest regex (currently Tar) - MAX_MAGIC_NUMBER_LENGTH = 262 - private_constant :MAX_MAGIC_NUMBER_LENGTH + module Magic + # length of the longest regex (currently Tar) + MAX_MAGIC_NUMBER_LENGTH = 262 + + refine Pathname do + def magic_number + @magic_number ||= if directory? + "" + else + binread(MAX_MAGIC_NUMBER_LENGTH) || "" + end + end + + def file_type + @file_type ||= system_command("file", args: ["-b", self], print_stderr: false) + .stdout.chomp + end + + def zipinfo + @zipinfo ||= system_command("zipinfo", args: ["-1", self], print_stderr: false) + .stdout + .encode(Encoding::UTF_8, invalid: :replace) + .split("\n") + end + end + end + private_constant :Magic def self.strategies @strategies ||= [ - Pkg, - Ttf, - Otf, - Air, - Executable, - SelfExtractingExecutable, - Jar, - LuaRock, - MicrosoftOfficeXml, - Zip, - Dmg, - Xar, - Compress, - Tar, - Bzip2, + Tar, # needs to be before Bzip2/Gzip/Xz/Lzma Gzip, Lzma, Xz, Lzip, + Air, # needs to be before Zip + Jar, # needs to be before Zip + LuaRock, # needs to be before Zip + MicrosoftOfficeXml, # needs to be before Zip + Zip, + Pkg, # needs to be before Xar + Xar, + Ttf, + Otf, Git, Mercurial, Subversion, Cvs, + SelfExtractingExecutable, # needs to be before Cab + Cab, + Executable, + Dmg, # needs to be before Bzip2 + Bzip2, Fossil, Bazaar, - Cab, + Compress, P7Zip, Sit, Rar, @@ -42,6 +66,7 @@ module UnpackStrategy def self.from_type(type) type = { naked: :uncompressed, + nounzip: :uncompressed, seven_zip: :p7zip, }.fetch(type, type) @@ -52,32 +77,30 @@ module UnpackStrategy end end - def self.from_path(path) - magic_number = if path.directory? - "" - else - File.binread(path, MAX_MAGIC_NUMBER_LENGTH) || "" - end - - strategy = strategies.detect do |s| - s.can_extract?(path: path, magic_number: magic_number) - end - - # This is so that bad files produce good error messages. - strategy ||= case path.extname - when ".tar", ".tar.gz", ".tgz", ".tar.bz2", ".tbz", ".tar.xz", ".txz" - Tar - when ".zip" - Zip - else - Uncompressed - end - - strategy + def self.from_extension(extension) + strategies.sort_by { |s| s.extensions.map(&:length).max(0) } + .reverse + .detect { |s| s.extensions.any? { |ext| extension.end_with?(ext) } } end - def self.detect(path, type: nil, ref_type: nil, ref: nil) - strategy = type ? from_type(type) : from_path(path) + def self.from_magic(path) + strategies.detect { |s| s.can_extract?(path) } + end + + def self.detect(path, extension_only: false, type: nil, ref_type: nil, ref: nil) + strategy = from_type(type) if type + + if extension_only + strategy ||= from_extension(path.extname) + strategy ||= strategies.select { |s| s < Directory || s == Fossil } + .detect { |s| s.can_extract?(path) } + else + strategy ||= from_magic(path) + strategy ||= from_extension(path.extname) + end + + strategy ||= Uncompressed + strategy.new(path, ref_type: ref_type, ref: ref) end @@ -96,7 +119,7 @@ module UnpackStrategy extract_to_dir(unpack_dir, basename: basename, verbose: verbose) end - def extract_nestedly(to: nil, basename: nil, verbose: false) + def extract_nestedly(to: nil, basename: nil, verbose: false, extension_only: false) Dir.mktmpdir do |tmp_unpack_dir| tmp_unpack_dir = Pathname(tmp_unpack_dir) @@ -105,9 +128,9 @@ module UnpackStrategy children = tmp_unpack_dir.children if children.count == 1 && !children.first.directory? - s = UnpackStrategy.detect(children.first) + s = UnpackStrategy.detect(children.first, extension_only: extension_only) - s.extract_nestedly(to: to, verbose: verbose) + s.extract_nestedly(to: to, verbose: verbose, extension_only: extension_only) next end diff --git a/Library/Homebrew/unpack_strategy/air.rb b/Library/Homebrew/unpack_strategy/air.rb index 4fd819c888..1b12e221b0 100644 --- a/Library/Homebrew/unpack_strategy/air.rb +++ b/Library/Homebrew/unpack_strategy/air.rb @@ -2,8 +2,15 @@ module UnpackStrategy class Air include UnpackStrategy - def self.can_extract?(path:, magic_number:) - path.extname == ".air" + using Magic + + def self.extensions + [".air"] + end + + def self.can_extract?(path) + mime_type = "application/vnd.adobe.air-application-installer-package+zip" + path.magic_number.match?(/.{59}#{Regexp.escape(mime_type)}/) end def dependencies diff --git a/Library/Homebrew/unpack_strategy/bazaar.rb b/Library/Homebrew/unpack_strategy/bazaar.rb index 4811d27279..684a5cad28 100644 --- a/Library/Homebrew/unpack_strategy/bazaar.rb +++ b/Library/Homebrew/unpack_strategy/bazaar.rb @@ -2,7 +2,9 @@ require_relative "directory" module UnpackStrategy class Bazaar < Directory - def self.can_extract?(path:, magic_number:) + using Magic + + def self.can_extract?(path) super && (path/".bzr").directory? end diff --git a/Library/Homebrew/unpack_strategy/bzip2.rb b/Library/Homebrew/unpack_strategy/bzip2.rb index 60378b7003..e47cc062df 100644 --- a/Library/Homebrew/unpack_strategy/bzip2.rb +++ b/Library/Homebrew/unpack_strategy/bzip2.rb @@ -2,8 +2,14 @@ module UnpackStrategy class Bzip2 include UnpackStrategy - def self.can_extract?(path:, magic_number:) - magic_number.match?(/\ABZh/n) + using Magic + + def self.extensions + [".bz2"] + end + + def self.can_extract?(path) + path.magic_number.match?(/\ABZh/n) end private diff --git a/Library/Homebrew/unpack_strategy/cab.rb b/Library/Homebrew/unpack_strategy/cab.rb index acc3b1ec32..afbf9e3784 100644 --- a/Library/Homebrew/unpack_strategy/cab.rb +++ b/Library/Homebrew/unpack_strategy/cab.rb @@ -2,8 +2,14 @@ module UnpackStrategy class Cab include UnpackStrategy - def self.can_extract?(path:, magic_number:) - magic_number.match?(/\AMSCF/n) + using Magic + + def self.extensions + [".cab"] + end + + def self.can_extract?(path) + path.magic_number.match?(/\AMSCF/n) end def extract_to_dir(unpack_dir, basename:, verbose:) diff --git a/Library/Homebrew/unpack_strategy/compress.rb b/Library/Homebrew/unpack_strategy/compress.rb index a1851ccf4d..952e17c980 100644 --- a/Library/Homebrew/unpack_strategy/compress.rb +++ b/Library/Homebrew/unpack_strategy/compress.rb @@ -2,8 +2,14 @@ require_relative "tar" module UnpackStrategy class Compress < Tar - def self.can_extract?(path:, magic_number:) - magic_number.match?(/\A\037\235/n) + using Magic + + def self.extensions + [".compress"] + end + + def self.can_extract?(path) + path.magic_number.match?(/\A\037\235/n) end end end diff --git a/Library/Homebrew/unpack_strategy/cvs.rb b/Library/Homebrew/unpack_strategy/cvs.rb index cca3010703..4ec2b03c23 100644 --- a/Library/Homebrew/unpack_strategy/cvs.rb +++ b/Library/Homebrew/unpack_strategy/cvs.rb @@ -2,7 +2,9 @@ require_relative "directory" module UnpackStrategy class Cvs < Directory - def self.can_extract?(path:, magic_number:) + using Magic + + def self.can_extract?(path) super && (path/"CVS").directory? end end diff --git a/Library/Homebrew/unpack_strategy/directory.rb b/Library/Homebrew/unpack_strategy/directory.rb index 540369de75..5aa39e9137 100644 --- a/Library/Homebrew/unpack_strategy/directory.rb +++ b/Library/Homebrew/unpack_strategy/directory.rb @@ -2,7 +2,13 @@ module UnpackStrategy class Directory include UnpackStrategy - def self.can_extract?(path:, magic_number:) + using Magic + + def self.extensions + [] + end + + def self.can_extract?(path) path.directory? end diff --git a/Library/Homebrew/unpack_strategy/dmg.rb b/Library/Homebrew/unpack_strategy/dmg.rb index 1068c93486..b15ec3c44d 100644 --- a/Library/Homebrew/unpack_strategy/dmg.rb +++ b/Library/Homebrew/unpack_strategy/dmg.rb @@ -4,6 +4,8 @@ module UnpackStrategy class Dmg include UnpackStrategy + using Magic + module Bom DMG_METADATA = Set.new %w[ .background @@ -83,12 +85,18 @@ module UnpackStrategy end system_command! "ditto", args: ["--bom", bomfile.path, "--", path, unpack_dir] + + FileUtils.chmod "u+w", Pathname.glob(unpack_dir/"**/*").reject(&:symlink?) end end end private_constant :Mount - def self.can_extract?(path:, magic_number:) + def self.extensions + [".dmg"] + end + + def self.can_extract?(path) imageinfo = system_command("hdiutil", args: ["imageinfo", path], print_stderr: false).stdout diff --git a/Library/Homebrew/unpack_strategy/executable.rb b/Library/Homebrew/unpack_strategy/executable.rb index 020a86b99f..3378bb6ff1 100644 --- a/Library/Homebrew/unpack_strategy/executable.rb +++ b/Library/Homebrew/unpack_strategy/executable.rb @@ -2,8 +2,15 @@ require_relative "uncompressed" module UnpackStrategy class Executable < Uncompressed - def self.can_extract?(path:, magic_number:) - magic_number.match?(/\A#!\s*\S+/n) + using Magic + + def self.extensions + [".sh", ".bash"] + end + + def self.can_extract?(path) + path.magic_number.match?(/\A#!\s*\S+/n) || + path.magic_number.match?(/\AMZ/n) end end end diff --git a/Library/Homebrew/unpack_strategy/fossil.rb b/Library/Homebrew/unpack_strategy/fossil.rb index 49b480ceab..5bc5e5e78f 100644 --- a/Library/Homebrew/unpack_strategy/fossil.rb +++ b/Library/Homebrew/unpack_strategy/fossil.rb @@ -2,8 +2,14 @@ module UnpackStrategy class Fossil include UnpackStrategy - def self.can_extract?(path:, magic_number:) - return false unless magic_number.match?(/\ASQLite format 3\000/n) + using Magic + + def self.extensions + [] + end + + def self.can_extract?(path) + return false unless path.magic_number.match?(/\ASQLite format 3\000/n) # Fossil database is made up of artifacts, so the `artifact` table must exist. query = "select count(*) from sqlite_master where type = 'view' and name = 'artifact'" diff --git a/Library/Homebrew/unpack_strategy/generic_unar.rb b/Library/Homebrew/unpack_strategy/generic_unar.rb index 3b11df94a4..f9e65b9dec 100644 --- a/Library/Homebrew/unpack_strategy/generic_unar.rb +++ b/Library/Homebrew/unpack_strategy/generic_unar.rb @@ -2,7 +2,13 @@ module UnpackStrategy class GenericUnar include UnpackStrategy - def self.can_extract?(path:, magic_number:) + using Magic + + def self.extensions + [] + end + + def self.can_extract?(_path) false end diff --git a/Library/Homebrew/unpack_strategy/git.rb b/Library/Homebrew/unpack_strategy/git.rb index 2f9f6668b1..2f5768ca54 100644 --- a/Library/Homebrew/unpack_strategy/git.rb +++ b/Library/Homebrew/unpack_strategy/git.rb @@ -2,7 +2,9 @@ require_relative "directory" module UnpackStrategy class Git < Directory - def self.can_extract?(path:, magic_number:) + using Magic + + def self.can_extract?(path) super && (path/".git").directory? end end diff --git a/Library/Homebrew/unpack_strategy/gzip.rb b/Library/Homebrew/unpack_strategy/gzip.rb index 6ae5517603..d575721d74 100644 --- a/Library/Homebrew/unpack_strategy/gzip.rb +++ b/Library/Homebrew/unpack_strategy/gzip.rb @@ -2,8 +2,14 @@ module UnpackStrategy class Gzip include UnpackStrategy - def self.can_extract?(path:, magic_number:) - magic_number.match?(/\A\037\213/n) + using Magic + + def self.extensions + [".gz"] + end + + def self.can_extract?(path) + path.magic_number.match?(/\A\037\213/n) end private diff --git a/Library/Homebrew/unpack_strategy/jar.rb b/Library/Homebrew/unpack_strategy/jar.rb index 35e2b211c0..90d4f6485c 100644 --- a/Library/Homebrew/unpack_strategy/jar.rb +++ b/Library/Homebrew/unpack_strategy/jar.rb @@ -2,14 +2,17 @@ require_relative "uncompressed" module UnpackStrategy class Jar < Uncompressed - def self.can_extract?(path:, magic_number:) - return false unless Zip.can_extract?(path: path, magic_number: magic_number) + using Magic + + def self.extensions + [".apk", ".jar"] + end + + def self.can_extract?(path) + return false unless Zip.can_extract?(path) # Check further if the ZIP is a JAR/WAR. - out, = Open3.capture3("zipinfo", "-1", path) - out.encode(Encoding::UTF_8, invalid: :replace) - .split("\n") - .include?("META-INF/MANIFEST.MF") + path.zipinfo.include?("META-INF/MANIFEST.MF") end end end diff --git a/Library/Homebrew/unpack_strategy/lha.rb b/Library/Homebrew/unpack_strategy/lha.rb index 9f71e75613..b3671b0a60 100644 --- a/Library/Homebrew/unpack_strategy/lha.rb +++ b/Library/Homebrew/unpack_strategy/lha.rb @@ -2,8 +2,14 @@ module UnpackStrategy class Lha include UnpackStrategy - def self.can_extract?(path:, magic_number:) - magic_number.match?(/\A..-(lh0|lh1|lz4|lz5|lzs|lh\\40|lhd|lh2|lh3|lh4|lh5)-/n) + using Magic + + def self.extensions + [".lha", ".lzh"] + end + + def self.can_extract?(path) + path.magic_number.match?(/\A..-(lh0|lh1|lz4|lz5|lzs|lh\\40|lhd|lh2|lh3|lh4|lh5)-/n) end def dependencies diff --git a/Library/Homebrew/unpack_strategy/lua_rock.rb b/Library/Homebrew/unpack_strategy/lua_rock.rb index d9a9c2e6ba..fe3d8f130b 100644 --- a/Library/Homebrew/unpack_strategy/lua_rock.rb +++ b/Library/Homebrew/unpack_strategy/lua_rock.rb @@ -2,14 +2,17 @@ require_relative "uncompressed" module UnpackStrategy class LuaRock < Uncompressed - def self.can_extract?(path:, magic_number:) - return false unless Zip.can_extract?(path: path, magic_number: magic_number) + using Magic + + def self.extensions + [".rock"] + end + + def self.can_extract?(path) + return false unless Zip.can_extract?(path) # Check further if the ZIP is a LuaRocks package. - out, = Open3.capture3("zipinfo", "-1", path) - out.encode(Encoding::UTF_8, invalid: :replace) - .split("\n") - .any? { |line| line.match?(%r{\A[^/]+.rockspec\Z}) } + path.zipinfo.grep(%r{\A[^/]+.rockspec\Z}).any? end end end diff --git a/Library/Homebrew/unpack_strategy/lzip.rb b/Library/Homebrew/unpack_strategy/lzip.rb index 21200c556d..f96e0ab2da 100644 --- a/Library/Homebrew/unpack_strategy/lzip.rb +++ b/Library/Homebrew/unpack_strategy/lzip.rb @@ -2,8 +2,14 @@ module UnpackStrategy class Lzip include UnpackStrategy - def self.can_extract?(path:, magic_number:) - magic_number.match?(/\ALZIP/n) + using Magic + + def self.extensions + [".lz"] + end + + def self.can_extract?(path) + path.magic_number.match?(/\ALZIP/n) end def dependencies diff --git a/Library/Homebrew/unpack_strategy/lzma.rb b/Library/Homebrew/unpack_strategy/lzma.rb index f759b0cb66..a9a60a0b9a 100644 --- a/Library/Homebrew/unpack_strategy/lzma.rb +++ b/Library/Homebrew/unpack_strategy/lzma.rb @@ -2,8 +2,14 @@ module UnpackStrategy class Lzma include UnpackStrategy - def self.can_extract?(path:, magic_number:) - magic_number.match?(/\A\]\000\000\200\000/n) + using Magic + + def self.extensions + [".lzma"] + end + + def self.can_extract?(path) + path.magic_number.match?(/\A\]\000\000\200\000/n) end def extract_to_dir(unpack_dir, basename:, verbose:) diff --git a/Library/Homebrew/unpack_strategy/mercurial.rb b/Library/Homebrew/unpack_strategy/mercurial.rb index 518878fdb2..34e897857c 100644 --- a/Library/Homebrew/unpack_strategy/mercurial.rb +++ b/Library/Homebrew/unpack_strategy/mercurial.rb @@ -2,7 +2,9 @@ require_relative "directory" module UnpackStrategy class Mercurial < Directory - def self.can_extract?(path:, magic_number:) + using Magic + + def self.can_extract?(path) super && (path/".hg").directory? end diff --git a/Library/Homebrew/unpack_strategy/microsoft_office_xml.rb b/Library/Homebrew/unpack_strategy/microsoft_office_xml.rb index 6f3501816f..50647869e2 100644 --- a/Library/Homebrew/unpack_strategy/microsoft_office_xml.rb +++ b/Library/Homebrew/unpack_strategy/microsoft_office_xml.rb @@ -2,12 +2,22 @@ require_relative "uncompressed" module UnpackStrategy class MicrosoftOfficeXml < Uncompressed - def self.can_extract?(path:, magic_number:) - return false unless Zip.can_extract?(path: path, magic_number: magic_number) + using Magic + + def self.extensions + [ + ".doc", ".docx", + ".ppt", ".pptx", + ".xls", ".xlsx" + ] + end + + def self.can_extract?(path) + return false unless Zip.can_extract?(path) # Check further if the ZIP is a Microsoft Office XML document. - magic_number.match?(/\APK\003\004/n) && - magic_number.match?(%r{\A.{30}(\[Content_Types\]\.xml|_rels/\.rels)}n) + path.magic_number.match?(/\APK\003\004/n) && + path.magic_number.match?(%r{\A.{30}(\[Content_Types\]\.xml|_rels/\.rels)}n) end end end diff --git a/Library/Homebrew/unpack_strategy/otf.rb b/Library/Homebrew/unpack_strategy/otf.rb index f8f4ee531f..a540f7779f 100644 --- a/Library/Homebrew/unpack_strategy/otf.rb +++ b/Library/Homebrew/unpack_strategy/otf.rb @@ -2,8 +2,14 @@ require_relative "uncompressed" module UnpackStrategy class Otf < Uncompressed - def self.can_extract?(path:, magic_number:) - magic_number.match?(/\AOTTO/n) + using Magic + + def self.extensions + [".otf"] + end + + def self.can_extract?(path) + path.magic_number.match?(/\AOTTO/n) end end end diff --git a/Library/Homebrew/unpack_strategy/p7zip.rb b/Library/Homebrew/unpack_strategy/p7zip.rb index 4a8d7d093b..cfb76d08c9 100644 --- a/Library/Homebrew/unpack_strategy/p7zip.rb +++ b/Library/Homebrew/unpack_strategy/p7zip.rb @@ -2,8 +2,14 @@ module UnpackStrategy class P7Zip include UnpackStrategy - def self.can_extract?(path:, magic_number:) - magic_number.match?(/\A7z\xBC\xAF\x27\x1C/n) + using Magic + + def self.extensions + [".7z"] + end + + def self.can_extract?(path) + path.magic_number.match?(/\A7z\xBC\xAF\x27\x1C/n) end def dependencies diff --git a/Library/Homebrew/unpack_strategy/pkg.rb b/Library/Homebrew/unpack_strategy/pkg.rb index dceee1ef56..f837d4933c 100644 --- a/Library/Homebrew/unpack_strategy/pkg.rb +++ b/Library/Homebrew/unpack_strategy/pkg.rb @@ -2,9 +2,15 @@ require_relative "uncompressed" module UnpackStrategy class Pkg < Uncompressed - def self.can_extract?(path:, magic_number:) + using Magic + + def self.extensions + [".pkg", ".mkpg"] + end + + def self.can_extract?(path) path.extname.match?(/\A.m?pkg\Z/) && - (path.directory? || magic_number.match?(/\Axar!/n)) + (path.directory? || path.magic_number.match?(/\Axar!/n)) end end end diff --git a/Library/Homebrew/unpack_strategy/rar.rb b/Library/Homebrew/unpack_strategy/rar.rb index d7ecbbf64a..648c79e972 100644 --- a/Library/Homebrew/unpack_strategy/rar.rb +++ b/Library/Homebrew/unpack_strategy/rar.rb @@ -2,8 +2,14 @@ module UnpackStrategy class Rar include UnpackStrategy - def self.can_extract?(path:, magic_number:) - magic_number.match?(/\ARar!/n) + using Magic + + def self.extensions + [".rar"] + end + + def self.can_extract?(path) + path.magic_number.match?(/\ARar!/n) end def dependencies diff --git a/Library/Homebrew/unpack_strategy/self_extracting_executable.rb b/Library/Homebrew/unpack_strategy/self_extracting_executable.rb index a7de316716..a502cce547 100644 --- a/Library/Homebrew/unpack_strategy/self_extracting_executable.rb +++ b/Library/Homebrew/unpack_strategy/self_extracting_executable.rb @@ -2,12 +2,15 @@ require_relative "generic_unar" module UnpackStrategy class SelfExtractingExecutable < GenericUnar - def self.can_extract?(path:, magic_number:) - return false unless magic_number.match?(/\AMZ/n) + using Magic - system_command("file", - args: [path], - print_stderr: false).stdout.include?("self-extracting") + def self.extensions + [] + end + + def self.can_extract?(path) + path.magic_number.match?(/\AMZ/n) && + path.file_type.include?("self-extracting archive") end end end diff --git a/Library/Homebrew/unpack_strategy/sit.rb b/Library/Homebrew/unpack_strategy/sit.rb index 48098bb8cb..c719de4a04 100644 --- a/Library/Homebrew/unpack_strategy/sit.rb +++ b/Library/Homebrew/unpack_strategy/sit.rb @@ -2,8 +2,14 @@ require_relative "generic_unar" module UnpackStrategy class Sit < GenericUnar - def self.can_extract?(path:, magic_number:) - magic_number.match?(/\AStuffIt/n) + using Magic + + def self.extensions + [".sit"] + end + + def self.can_extract?(path) + path.magic_number.match?(/\AStuffIt/n) end end end diff --git a/Library/Homebrew/unpack_strategy/subversion.rb b/Library/Homebrew/unpack_strategy/subversion.rb index 064baf921a..3824dce378 100644 --- a/Library/Homebrew/unpack_strategy/subversion.rb +++ b/Library/Homebrew/unpack_strategy/subversion.rb @@ -2,7 +2,9 @@ require_relative "directory" module UnpackStrategy class Subversion < Directory - def self.can_extract?(path:, magic_number:) + using Magic + + def self.can_extract?(path) super && (path/".svn").directory? end diff --git a/Library/Homebrew/unpack_strategy/tar.rb b/Library/Homebrew/unpack_strategy/tar.rb index 704e3890f4..a21682050d 100644 --- a/Library/Homebrew/unpack_strategy/tar.rb +++ b/Library/Homebrew/unpack_strategy/tar.rb @@ -2,8 +2,24 @@ module UnpackStrategy class Tar include UnpackStrategy - def self.can_extract?(path:, magic_number:) - return true if magic_number.match?(/\A.{257}ustar/n) + using Magic + + def self.extensions + [ + ".tar", + ".tbz", ".tbz2", ".tar.bz2", + ".tgz", ".tar.gz", + ".tlz", ".tar.lz", + ".txz", ".tar.xz" + ] + end + + def self.can_extract?(path) + return true if path.magic_number.match?(/\A.{257}ustar/n) + + unless [Bzip2, Gzip, Lzip, Xz].any? { |s| s.can_extract?(path) } + return false + end # Check if `tar` can list the contents, then it can also extract it. IO.popen(["tar", "tf", path], err: File::NULL) do |stdout| @@ -14,7 +30,17 @@ module UnpackStrategy private def extract_to_dir(unpack_dir, basename:, verbose:) - system_command! "tar", args: ["xf", path, "-C", unpack_dir] + 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) + tar_path = tmpdir.children.first + end + + system_command! "tar", args: ["xf", tar_path, "-C", unpack_dir] + end end end end diff --git a/Library/Homebrew/unpack_strategy/ttf.rb b/Library/Homebrew/unpack_strategy/ttf.rb index 8d1421a106..e5f0540c0b 100644 --- a/Library/Homebrew/unpack_strategy/ttf.rb +++ b/Library/Homebrew/unpack_strategy/ttf.rb @@ -2,11 +2,17 @@ require_relative "uncompressed" module UnpackStrategy class Ttf < Uncompressed - def self.can_extract?(path:, magic_number:) + using Magic + + def self.extensions + [".ttc", ".ttf"] + end + + def self.can_extract?(path) # TrueType Font - magic_number.match?(/\A\000\001\000\000\000/n) || + path.magic_number.match?(/\A\000\001\000\000\000/n) || # Truetype Font Collection - magic_number.match?(/\Attcf/n) + path.magic_number.match?(/\Attcf/n) end end end diff --git a/Library/Homebrew/unpack_strategy/uncompressed.rb b/Library/Homebrew/unpack_strategy/uncompressed.rb index b3facb172c..fe627bf818 100644 --- a/Library/Homebrew/unpack_strategy/uncompressed.rb +++ b/Library/Homebrew/unpack_strategy/uncompressed.rb @@ -2,7 +2,9 @@ module UnpackStrategy class Uncompressed include UnpackStrategy - alias extract_nestedly extract + def extract_nestedly(extension_only: false, **options) + extract(**options) + end private diff --git a/Library/Homebrew/unpack_strategy/xar.rb b/Library/Homebrew/unpack_strategy/xar.rb index b631aba77d..043c6a5f49 100644 --- a/Library/Homebrew/unpack_strategy/xar.rb +++ b/Library/Homebrew/unpack_strategy/xar.rb @@ -2,8 +2,14 @@ module UnpackStrategy class Xar include UnpackStrategy - def self.can_extract?(path:, magic_number:) - magic_number.match?(/\Axar!/n) + using Magic + + def self.extensions + [".xar"] + end + + def self.can_extract?(path) + path.magic_number.match?(/\Axar!/n) end private diff --git a/Library/Homebrew/unpack_strategy/xz.rb b/Library/Homebrew/unpack_strategy/xz.rb index c7f418cede..99673e6159 100644 --- a/Library/Homebrew/unpack_strategy/xz.rb +++ b/Library/Homebrew/unpack_strategy/xz.rb @@ -2,8 +2,14 @@ module UnpackStrategy class Xz include UnpackStrategy - def self.can_extract?(path:, magic_number:) - magic_number.match?(/\A\xFD7zXZ\x00/n) + using Magic + + def self.extensions + [".xz"] + end + + def self.can_extract?(path) + path.magic_number.match?(/\A\xFD7zXZ\x00/n) end def dependencies @@ -18,19 +24,6 @@ module UnpackStrategy system_command! "unxz", args: [*quiet_flags, "-T0", "--", unpack_dir/basename], env: { "PATH" => PATH.new(Formula["xz"].opt_bin, ENV["PATH"]) } - extract_nested_tar(unpack_dir) - end - - def extract_nested_tar(unpack_dir) - return unless DependencyCollector.tar_needs_xz_dependency? - return if (children = unpack_dir.children).count != 1 - return if (tar = children.first).extname != ".tar" - - Dir.mktmpdir do |tmpdir| - tmpdir = Pathname(tmpdir) - FileUtils.mv tar, tmpdir/tar.basename - Tar.new(tmpdir/tar.basename).extract(to: unpack_dir) - end end end end diff --git a/Library/Homebrew/unpack_strategy/zip.rb b/Library/Homebrew/unpack_strategy/zip.rb index df3a0c1220..d8188447ba 100644 --- a/Library/Homebrew/unpack_strategy/zip.rb +++ b/Library/Homebrew/unpack_strategy/zip.rb @@ -2,8 +2,14 @@ module UnpackStrategy class Zip include UnpackStrategy - def self.can_extract?(path:, magic_number:) - magic_number.match?(/\APK(\003\004|\005\006)/n) + using Magic + + def self.extensions + [".zip"] + end + + def self.can_extract?(path) + path.magic_number.match?(/\APK(\003\004|\005\006)/n) end private