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.

unzip

Fetch.unzip
fn unzip(
    f: *Fetch,
    out_dir: Io.Dir,
    reader: *Io.Reader,
) error

File

lib/compiler/Maker/Fetch.zig:1483

Code

fn unzip(
    f: *Fetch,
    out_dir: Io.Dir,
    reader: *Io.Reader,
) error{ ReadFailed, OutOfMemory, Canceled, FetchFailed }!UnpackResult {
    // We write the entire contents to a file first because zip files
    // must be processed back to front and they could be too large to
    // load into memory.

    const io = f.job_queue.io;
    const cache_root = f.job_queue.global_cache;
    const prefix = "tmp/";
    const suffix = ".zip";
    const eb = &f.error_bundle;
    const random_len = @sizeOf(u64) * 2;

    var zip_path: [prefix.len + random_len + suffix.len]u8 = undefined;
    zip_path[0..prefix.len].* = prefix.*;
    zip_path[prefix.len + random_len ..].* = suffix.*;

    var zip_file = while (true) {
        const random_integer = r: {
            var x: u64 = undefined;
            io.random(@ptrCast(&x));
            break :r x;
        };
        zip_path[prefix.len..][0..random_len].* = std.fmt.hex(random_integer);

        break cache_root.handle.createFile(io, &zip_path, .{
            .exclusive = true,
            .read = true,
        }) catch |err| switch (err) {
            error.PathAlreadyExists => continue,
            error.FileNotFound => {
                cache_root.handle.createDir(io, prefix, .default_dir) catch |dir_err| switch (dir_err) {
                    error.Canceled => |e| return e,
                    // error.PathAlreadyExists is considered a failure here because
                    // it implies that the prefix is not a directory.
                    else => |e| return f.fail(
                        f.location_tok,
                        try eb.printString("failed to create temporary directory: {t}", .{e}),
                    ),
                };
                continue;
            },
            error.Canceled => |e| return e,
            else => |e| return f.fail(
                f.location_tok,
                try eb.printString("failed to create temporary zip file: {t}", .{e}),
            ),
        };
    };
    defer zip_file.close(io);
    var zip_file_buffer: [4096]u8 = undefined;
    var zip_file_reader = b: {
        var zip_file_writer = zip_file.writer(io, &zip_file_buffer);

        _ = reader.streamRemaining(&zip_file_writer.interface) catch |err| switch (err) {
            error.ReadFailed => |e| return e,
            error.WriteFailed => return f.fail(
                f.location_tok,
                try eb.printString("failed writing temporary zip file: {t}", .{err}),
            ),
        };
        zip_file_writer.interface.flush() catch |err| return f.fail(
            f.location_tok,
            try eb.printString("failed writing temporary zip file: {t}", .{err}),
        );
        break :b zip_file_writer.moveToReader();
    };

    var diagnostics: std.zip.Diagnostics = .{ .allocator = f.arena.allocator() };
    // no need to deinit since we are using an arena allocator

    zip_file_reader.seekTo(0) catch |err|
        return f.fail(f.location_tok, try eb.printString("failed to seek temporary zip file: {t}", .{err}));
    std.zip.extract(out_dir, &zip_file_reader, .{
        .allow_backslashes = true,
        .diagnostics = &diagnostics,
    }) catch |err| return f.fail(f.location_tok, try eb.printString("zip extract failed: {t}", .{err}));

    cache_root.handle.deleteFile(io, &zip_path) catch |err|
        return f.fail(f.location_tok, try eb.printString("delete temporary zip failed: {t}", .{err}));

    return .{ .root_dir = diagnostics.root_dir };
}