require 'net/http' require 'uri' require 'open3' require 'fileutils' require 'open-uri' module Archive MAGIC_NUMBERS = { "\x1F\x8B" => 'gzip', "\x50\x4B\x03\x04" => 'zip', "\x28\xB5\x2F\xFD" => 'zstd', "\xFD\x37\x7A\x58" => 'xz' } def self.detect_format_from_url(url) case File.extname(url) when '.gz', '.tgz' then 'gzip' when '.zip' then 'zip' when '.zst' then 'zstd' when '.xz' then 'xz' else nil end end def self.detect_format_from_headers(uri) response = Net::HTTP.get_response(uri) content_type = response['content-type'] case content_type when /gzip/ then 'gzip' when /zip/ then 'zip' when /zstd/ then 'zstd' when /xz/ then 'xz' else nil end end def self.detect_format_from_magic(file_path) File.open(file_path, 'rb') do |f| bytes = f.read(4) MAGIC_NUMBERS.each do |magic, format| return format if bytes.start_with?(magic) end end nil end def self.download_file(uri, output_path) URI.open(uri) do |input| File.open(output_path, 'wb') do |output| IO.copy_stream(input, output) end end end def self.extract_archive(file_path, format) case format when 'gzip' system("tar -xzf #{Shellwords.escape(file_path)}") when 'zip' system("unzip #{Shellwords.escape(file_path)}") when 'zstd' system("unzstd #{Shellwords.escape(file_path)}") when 'xz' system("tar -xJf #{Shellwords.escape(file_path)}") else raise "Unsupported archive format: #{format}" end end def self.fetch_and_extract(url) uri = URI.parse(url) file_name = File.basename(uri.path) tmp_path = "/tmp/#{file_name}" format = detect_format_from_url(url) puts "format #{format}" download_file(uri, tmp_path) unless format format = detect_format_from_headers(uri) end unless format format = detect_format_from_magic(tmp_path) end raise "Could not determine archive format" unless format extract_archive(tmp_path, format) end end # Example usage: # fetch_and_extract("https://codeberg.org/forgejo/forgejo/releases/download/v12.0.1/forgejo-12.0.1-linux-amd64.xz")