From 3013fda863b0a680455bb87485ffa0a0d71a5fc3 Mon Sep 17 00:00:00 2001 From: Artur Gurgul Date: Mon, 4 Aug 2025 19:43:28 +0200 Subject: [PATCH] Add download manager --- lib/archive.rb | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 lib/archive.rb diff --git a/lib/archive.rb b/lib/archive.rb new file mode 100644 index 0000000..d8fde1b --- /dev/null +++ b/lib/archive.rb @@ -0,0 +1,93 @@ +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")