brew/Library/Homebrew/unpack_strategy.rb
Mike McQuaid 20e4262fb9
unpack_strategy: prioritise extension instead.
Instead of only looking at the extension when invoked as part of
Homebrew's formulae' download strategies instead prioritise the
extension if it actually exists. When it does not, fall back to the
magic detection logic which is likely to be more reliable.

Fixes https://github.com/Homebrew/brew/issues/5895
2019-04-03 10:32:29 +01:00

185 lines
4.9 KiB
Ruby

module UnpackStrategy
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 ||= [
Tar, # needs to be before Bzip2/Gzip/Xz/Lzma
Pax,
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,
Compress,
P7Zip,
Sit,
Rar,
Lha,
].freeze
end
private_class_method :strategies
def self.from_type(type)
type = {
naked: :uncompressed,
nounzip: :uncompressed,
seven_zip: :p7zip,
}.fetch(type, type)
begin
const_get(type.to_s.split("_").map(&:capitalize).join.gsub(/\d+[a-z]/, &:upcase))
rescue NameError
nil
end
end
def self.from_extension(extension)
strategies.sort_by { |s| s.extensions.map(&:length).max || 0 }
.reverse
.find { |s| s.extensions.any? { |ext| extension.end_with?(ext) } }
end
def self.from_magic(path)
strategies.find { |s| s.can_extract?(path) }
end
def self.detect(path, prioritise_extension: false, type: nil, ref_type: nil, ref: nil)
strategy = from_type(type) if type
if prioritise_extension && path.extname.present?
strategy ||= from_extension(path.extname)
strategy ||= strategies.select { |s| s < Directory || s == Fossil }
.find { |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
attr_reader :path
def initialize(path, ref_type: nil, ref: nil)
@path = Pathname(path).expand_path
@ref_type = ref_type
@ref = ref
end
def extract(to: nil, basename: nil, verbose: false)
basename ||= path.basename
unpack_dir = Pathname(to || Dir.pwd).expand_path
unpack_dir.mkpath
extract_to_dir(unpack_dir, basename: basename, verbose: verbose)
end
def extract_nestedly(to: nil, basename: nil, verbose: false, prioritise_extension: false)
Dir.mktmpdir do |tmp_unpack_dir|
tmp_unpack_dir = Pathname(tmp_unpack_dir)
extract(to: tmp_unpack_dir, basename: basename, verbose: verbose)
children = tmp_unpack_dir.children
if children.count == 1 && !children.first.directory?
FileUtils.chmod "+rw", children.first, verbose: verbose
s = UnpackStrategy.detect(children.first, prioritise_extension: prioritise_extension)
s.extract_nestedly(to: to, verbose: verbose, prioritise_extension: prioritise_extension)
next
end
Directory.new(tmp_unpack_dir).extract(to: to, verbose: verbose)
FileUtils.chmod_R "+w", tmp_unpack_dir, force: true, verbose: verbose
end
end
def dependencies
[]
end
end
require "unpack_strategy/air"
require "unpack_strategy/bazaar"
require "unpack_strategy/bzip2"
require "unpack_strategy/cab"
require "unpack_strategy/compress"
require "unpack_strategy/cvs"
require "unpack_strategy/directory"
require "unpack_strategy/dmg"
require "unpack_strategy/executable"
require "unpack_strategy/fossil"
require "unpack_strategy/generic_unar"
require "unpack_strategy/git"
require "unpack_strategy/gzip"
require "unpack_strategy/jar"
require "unpack_strategy/lha"
require "unpack_strategy/lua_rock"
require "unpack_strategy/lzip"
require "unpack_strategy/lzma"
require "unpack_strategy/mercurial"
require "unpack_strategy/microsoft_office_xml"
require "unpack_strategy/otf"
require "unpack_strategy/p7zip"
require "unpack_strategy/pax"
require "unpack_strategy/pkg"
require "unpack_strategy/rar"
require "unpack_strategy/self_extracting_executable"
require "unpack_strategy/sit"
require "unpack_strategy/subversion"
require "unpack_strategy/tar"
require "unpack_strategy/ttf"
require "unpack_strategy/uncompressed"
require "unpack_strategy/xar"
require "unpack_strategy/xz"
require "unpack_strategy/zip"