| ... | @@ -756,12 +756,14 @@ const FileType = enum { | ... | @@ -756,12 +756,14 @@ const FileType = enum { |
| 756 | tar, | 756 | tar, |
| 757 | @"tar.gz", | 757 | @"tar.gz", |
| 758 | @"tar.xz", | 758 | @"tar.xz", |
| | 759 | @"tar.zst", |
| 759 | git_pack, | 760 | git_pack, |
| 760 | | 761 | |
| 761 | fn fromPath(file_path: []const u8) ?FileType { | 762 | fn fromPath(file_path: []const u8) ?FileType { |
| 762 | if (ascii.endsWithIgnoreCase(file_path, ".tar")) return .tar; | 763 | if (ascii.endsWithIgnoreCase(file_path, ".tar")) return .tar; |
| 763 | if (ascii.endsWithIgnoreCase(file_path, ".tar.gz")) return .@"tar.gz"; | 764 | if (ascii.endsWithIgnoreCase(file_path, ".tar.gz")) return .@"tar.gz"; |
| 764 | if (ascii.endsWithIgnoreCase(file_path, ".tar.xz")) return .@"tar.xz"; | 765 | if (ascii.endsWithIgnoreCase(file_path, ".tar.xz")) return .@"tar.xz"; |
| | 766 | if (ascii.endsWithIgnoreCase(file_path, ".tar.zst")) return .@"tar.zst"; |
| 765 | return null; | 767 | return null; |
| 766 | } | 768 | } |
| 767 | | 769 | |
| ... | @@ -979,6 +981,9 @@ fn unpackResource( | ... | @@ -979,6 +981,9 @@ fn unpackResource( |
| 979 | if (ascii.eqlIgnoreCase(content_type, "application/x-xz")) | 981 | if (ascii.eqlIgnoreCase(content_type, "application/x-xz")) |
| 980 | break :ft .@"tar.xz"; | 982 | break :ft .@"tar.xz"; |
| 981 | | 983 | |
| | 984 | if (ascii.eqlIgnoreCase(content_type, "application/zstd")) |
| | 985 | break :ft .@"tar.zst"; |
| | 986 | |
| 982 | if (!ascii.eqlIgnoreCase(content_type, "application/octet-stream")) { | 987 | if (!ascii.eqlIgnoreCase(content_type, "application/octet-stream")) { |
| 983 | return f.fail(f.location_tok, try eb.printString( | 988 | return f.fail(f.location_tok, try eb.printString( |
| 984 | "unrecognized 'Content-Type' header: '{s}'", | 989 | "unrecognized 'Content-Type' header: '{s}'", |
| ... | @@ -1019,6 +1024,7 @@ fn unpackResource( | ... | @@ -1019,6 +1024,7 @@ fn unpackResource( |
| 1019 | .tar => try unpackTarball(f, tmp_directory.handle, resource.reader()), | 1024 | .tar => try unpackTarball(f, tmp_directory.handle, resource.reader()), |
| 1020 | .@"tar.gz" => try unpackTarballCompressed(f, tmp_directory.handle, resource, std.compress.gzip), | 1025 | .@"tar.gz" => try unpackTarballCompressed(f, tmp_directory.handle, resource, std.compress.gzip), |
| 1021 | .@"tar.xz" => try unpackTarballCompressed(f, tmp_directory.handle, resource, std.compress.xz), | 1026 | .@"tar.xz" => try unpackTarballCompressed(f, tmp_directory.handle, resource, std.compress.xz), |
| | 1027 | .@"tar.zst" => try unpackTarballCompressed(f, tmp_directory.handle, resource, ZstdWrapper), |
| 1022 | .git_pack => unpackGitPack(f, tmp_directory.handle, resource) catch |err| switch (err) { | 1028 | .git_pack => unpackGitPack(f, tmp_directory.handle, resource) catch |err| switch (err) { |
| 1023 | error.FetchFailed => return error.FetchFailed, | 1029 | error.FetchFailed => return error.FetchFailed, |
| 1024 | error.OutOfMemory => return error.OutOfMemory, | 1030 | error.OutOfMemory => return error.OutOfMemory, |
| ... | @@ -1030,6 +1036,18 @@ fn unpackResource( | ... | @@ -1030,6 +1036,18 @@ fn unpackResource( |
| 1030 | } | 1036 | } |
| 1031 | } | 1037 | } |
| 1032 | | 1038 | |
| | 1039 | // due to slight differences in the API of std.compress.(gzip|xz) and std.compress.zstd, zstd is |
| | 1040 | // wrapped for generic use in unpackTarballCompressed: see github.com/ziglang/zig/issues/14739 |
| | 1041 | const ZstdWrapper = struct { |
| | 1042 | fn DecompressType(comptime T: type) type { |
| | 1043 | return error{}!std.compress.zstd.DecompressStream(T, .{}); |
| | 1044 | } |
| | 1045 | |
| | 1046 | fn decompress(allocator: Allocator, reader: anytype) DecompressType(@TypeOf(reader)) { |
| | 1047 | return std.compress.zstd.decompressStream(allocator, reader); |
| | 1048 | } |
| | 1049 | }; |
| | 1050 | |
| 1033 | fn unpackTarballCompressed( | 1051 | fn unpackTarballCompressed( |
| 1034 | f: *Fetch, | 1052 | f: *Fetch, |
| 1035 | out_dir: fs.Dir, | 1053 | out_dir: fs.Dir, |