feature. See also
. The project being documented here (as the example) is the Zig library itself.
Fetch.unzip
fn unzip(
f: *Fetch,
out_dir: Io.Dir,
reader: *Io.Reader,
) error
File
Code
fn unzip(
f: *Fetch,
out_dir: Io.Dir,
reader: *Io.Reader,
) error{ ReadFailed, OutOfMemory, Canceled, FetchFailed }!UnpackResult {
// 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,
// 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() };
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 };
}