From d94613c1d06fbeaf0cee88a04842cda64a10c8f9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 24 Jan 2023 15:09:02 -0700 Subject: [PATCH] support xz compressed tarballs in the package manager This includes a breaking change: std.compress.gzip.GzipStream renamed to std.compress.gzip.Decompress This follows the same naming convention as std.compress.xz so that the stream type can be passed as a comptime parameter. --- lib/std/compress/gzip.zig | 13 +++++-------- src/Package.zig | 29 +++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/lib/std/compress/gzip.zig b/lib/std/compress/gzip.zig index 4d1f8e28f4..7e9fea6814 100644 --- a/lib/std/compress/gzip.zig +++ b/lib/std/compress/gzip.zig @@ -1,7 +1,7 @@ // // Decompressor for GZIP data streams (RFC1952) -const std = @import("std"); +const std = @import("../std.zig"); const io = std.io; const fs = std.fs; const testing = std.testing; @@ -17,10 +17,7 @@ const FCOMMENT = 1 << 4; const max_string_len = 1024; -/// TODO: the fully qualified namespace to this declaration is -/// std.compress.gzip.GzipStream which has a redundant "gzip" in the name. -/// Instead, it should be `std.compress.gzip.Stream`. -pub fn GzipStream(comptime ReaderType: type) type { +pub fn Decompress(comptime ReaderType: type) type { return struct { const Self = @This(); @@ -154,14 +151,14 @@ pub fn GzipStream(comptime ReaderType: type) type { }; } -pub fn gzipStream(allocator: mem.Allocator, reader: anytype) !GzipStream(@TypeOf(reader)) { - return GzipStream(@TypeOf(reader)).init(allocator, reader); +pub fn decompress(allocator: mem.Allocator, reader: anytype) !Decompress(@TypeOf(reader)) { + return Decompress(@TypeOf(reader)).init(allocator, reader); } fn testReader(data: []const u8, comptime expected: []const u8) !void { var in_stream = io.fixedBufferStream(data); - var gzip_stream = try gzipStream(testing.allocator, in_stream.reader()); + var gzip_stream = try decompress(testing.allocator, in_stream.reader()); defer gzip_stream.deinit(); // Read and decompress the whole file diff --git a/src/Package.zig b/src/Package.zig index f8823cc74e..ebe84b8444 100644 --- a/src/Package.zig +++ b/src/Package.zig @@ -370,14 +370,11 @@ fn fetchAndUnpack( if (mem.endsWith(u8, uri.path, ".tar.gz")) { // I observed the gzip stream to read 1 byte at a time, so I am using a // buffered reader on the front of it. - var br = std.io.bufferedReaderSize(std.crypto.tls.max_ciphertext_record_len, req.reader()); - - var gzip_stream = try std.compress.gzip.gzipStream(gpa, br.reader()); - defer gzip_stream.deinit(); - - try std.tar.pipeToFileSystem(tmp_directory.handle, gzip_stream.reader(), .{ - .strip_components = 1, - }); + try unpackTarball(gpa, &req, tmp_directory.handle, std.compress.gzip); + } else if (mem.endsWith(u8, uri.path, ".tar.xz")) { + // I have not checked what buffer sizes the xz decompression implementation uses + // by default, so the same logic applies for buffering the reader as for gzip. + try unpackTarball(gpa, &req, tmp_directory.handle, std.compress.xz); } else { return reportError( ini, @@ -430,6 +427,22 @@ fn fetchAndUnpack( return createWithDir(gpa, fqn, global_cache_directory, pkg_dir_sub_path, build_zig_basename); } +fn unpackTarball( + gpa: Allocator, + req: *std.http.Client.Request, + out_dir: fs.Dir, + comptime compression: type, +) !void { + var br = std.io.bufferedReaderSize(std.crypto.tls.max_ciphertext_record_len, req.reader()); + + var decompress = try compression.decompress(gpa, br.reader()); + defer decompress.deinit(); + + try std.tar.pipeToFileSystem(out_dir, decompress.reader(), .{ + .strip_components = 1, + }); +} + fn reportError( ini: std.Ini, comp_directory: Compilation.Directory,