Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

unpackResource

Fetch.unpackResource
fn unpackResource(
    f: *Fetch,
    resource: *Resource,
    uri_path: []const u8,
    tmp_directory: Directory,
) RunError!UnpackResult

File

lib/compiler/Maker/Fetch.zig:1328

Code

fn unpackResource(
    f: *Fetch,
    resource: *Resource,
    uri_path: []const u8,
    tmp_directory: Directory,
) RunError!UnpackResult {
    const eb = &f.error_bundle;
    const file_type = switch (resource.*) {
        .file => FileType.fromPath(uri_path) orelse
            return f.fail(f.location_tok, try eb.printString("unknown file type: '{s}'", .{uri_path})),

        .http_request => |*http_request| ft: {
            const head = &http_request.response.head;

            // Content-Type takes first precedence.
            const content_type = head.content_type orelse
                return f.fail(f.location_tok, try eb.addString("missing 'Content-Type' header"));

            // Extract the MIME type, ignoring charset and boundary directives
            const mime_type_end = std.mem.indexOf(u8, content_type, ";") orelse content_type.len;
            const mime_type = content_type[0..mime_type_end];

            if (ascii.eqlIgnoreCase(mime_type, "application/x-tar"))
                break :ft .tar;

            if (ascii.eqlIgnoreCase(mime_type, "application/gzip") or
                ascii.eqlIgnoreCase(mime_type, "application/x-gzip") or
                ascii.eqlIgnoreCase(mime_type, "application/tar+gzip") or
                ascii.eqlIgnoreCase(mime_type, "application/x-tar-gz") or
                ascii.eqlIgnoreCase(mime_type, "application/x-gtar-compressed"))
            {
                break :ft .@"tar.gz";
            }

            if (ascii.eqlIgnoreCase(mime_type, "application/x-xz"))
                break :ft .@"tar.xz";

            if (ascii.eqlIgnoreCase(mime_type, "application/zstd"))
                break :ft .@"tar.zst";

            if (ascii.eqlIgnoreCase(mime_type, "application/zip") or
                ascii.eqlIgnoreCase(mime_type, "application/x-zip-compressed") or
                ascii.eqlIgnoreCase(mime_type, "application/java-archive"))
            {
                break :ft .zip;
            }

            if (!ascii.eqlIgnoreCase(mime_type, "application/octet-stream") and
                !ascii.eqlIgnoreCase(mime_type, "application/x-compressed"))
            {
                return f.fail(f.location_tok, try eb.printString(
                    "unrecognized 'Content-Type' header: '{s}'",
                    .{content_type},
                ));
            }

            // Next, the filename from 'content-disposition: attachment' takes precedence.
            if (head.content_disposition) |cd_header| {
                break :ft FileType.fromContentDisposition(cd_header) orelse {
                    return f.fail(f.location_tok, try eb.printString(
                        "unsupported Content-Disposition header value: '{s}' for Content-Type=application/octet-stream",
                        .{cd_header},
                    ));
                };
            }

            // Finally, the path from the URI is used.
            break :ft FileType.fromPath(uri_path) orelse {
                return f.fail(f.location_tok, try eb.printString("unknown file type: '{s}'", .{uri_path}));
            };
        },

        .git => .git_pack,

        .dir => |dir| {
            f.recursiveDirectoryCopy(dir, tmp_directory.handle) catch |err| {
                return f.fail(f.location_tok, try eb.printString("unable to copy directory '{s}': {t}", .{
                    uri_path, err,
                }));
            };
            return .{};
        },
    };

    switch (file_type) {
        .tar => {
            return unpackTarball(f, tmp_directory.handle, resource.reader());
        },
        .@"tar.gz" => {
            var flate_buffer: [std.compress.flate.max_window_len]u8 = undefined;
            var decompress: std.compress.flate.Decompress = .init(resource.reader(), .gzip, &flate_buffer);
            return try unpackTarball(f, tmp_directory.handle, &decompress.reader);
        },
        .@"tar.xz" => {
            const gpa = f.arena.child_allocator;
            var decompress = std.compress.xz.Decompress.init(resource.reader(), gpa, &.{}) catch |err|
                return f.fail(f.location_tok, try eb.printString("unable to decompress tarball: {t}", .{err}));
            defer decompress.deinit();
            return try unpackTarball(f, tmp_directory.handle, &decompress.reader);
        },
        .@"tar.zst" => {
            const window_len = std.compress.zstd.default_window_len;
            const window_buffer = try f.arena.allocator().alloc(u8, window_len + std.compress.zstd.block_size_max);
            var decompress: std.compress.zstd.Decompress = .init(resource.reader(), window_buffer, .{
                .verify_checksum = false,
                .window_len = window_len,
            });
            return try unpackTarball(f, tmp_directory.handle, &decompress.reader);
        },
        .git_pack => return unpackGitPack(f, tmp_directory.handle, &resource.git) catch |err| switch (err) {
            error.FetchFailed, error.OutOfMemory => |e| return e,
            else => |e| return f.fail(f.location_tok, try eb.printString("unable to unpack git files: {t}", .{e})),
        },
        .zip => return unzip(f, tmp_directory.handle, resource.reader()) catch |err| switch (err) {
            error.ReadFailed => return f.fail(f.location_tok, try eb.printString(
                "failed reading resource: {t}",
                .{err},
            )),
            else => |e| return e,
        },
    }
}