feature. See also
. The project being documented here (as the example) is the Zig library itself.
Fetch.initResource
fn initResource(f: *Fetch, uri: std.Uri, resource: *Resource, reader_buffer: []u8) RunError!void
File
Code
fn initResource(f: *Fetch, uri: std.Uri, resource: *Resource, reader_buffer: []u8) RunError!void {
const io = f.job_queue.io;
const arena = f.arena.allocator();
const eb = &f.error_bundle;
if (ascii.eqlIgnoreCase(uri.scheme, "file")) {
const path = try uri.path.toRawMaybeAlloc(arena);
const file = f.parent_package_root.openFile(io, path, .{}) catch |err| {
return f.fail(f.location_tok, try eb.printString("unable to open {f}/{s}: {t}", .{
f.parent_package_root, path, err,
}));
};
resource.* = .{ .file = file.reader(io, reader_buffer) };
return;
}
const http_client = f.job_queue.http_client;
if (ascii.eqlIgnoreCase(uri.scheme, "http") or
ascii.eqlIgnoreCase(uri.scheme, "https"))
{
resource.* = .{ .http_request = .{
.request = http_client.request(.GET, uri, .{}) catch |err|
return f.fail(f.location_tok, try eb.printString("server connection failed: {t}", .{err})),
.response = undefined,
.transfer_buffer = reader_buffer,
.decompress_buffer = &.{},
.decompress = undefined,
} };
const request = &resource.http_request.request;
errdefer request.deinit();
request.sendBodiless() catch |err|
return f.fail(f.location_tok, try eb.printString("HTTP request failed: {t}", .{err}));
var redirect_buffer: [8000]u8 = undefined;
const response = &resource.http_request.response;
response.* = request.receiveHead(&redirect_buffer) catch |err| switch (err) {
error.ReadFailed => {
return f.fail(f.location_tok, try eb.printString("HTTP response read failure: {t}", .{
request.connection.?.getReadError().?,
}));
},
else => |e| return f.fail(f.location_tok, try eb.printString("invalid HTTP response: {t}", .{e})),
};
if (response.head.status != .ok) return f.fail(f.location_tok, try eb.printString(
"bad HTTP response code: '{d} {s}'",
.{ response.head.status, response.head.status.phrase() orelse "" },
));
resource.http_request.decompress_buffer = try arena.alloc(u8, response.head.content_encoding.minBufferCapacity());
return;
}
if (ascii.eqlIgnoreCase(uri.scheme, "git+http") or
ascii.eqlIgnoreCase(uri.scheme, "git+https"))
{
var transport_uri = uri;
transport_uri.scheme = uri.scheme["git+".len..];
var session = git.Session.init(arena, http_client, transport_uri, reader_buffer) catch |err| {
return f.fail(
f.location_tok,
try eb.printString("unable to discover remote git server capabilities: {t}", .{err}),
);
};
const want_oid = want_oid: {
const want_ref =
if (uri.fragment) |fragment| try fragment.toRawMaybeAlloc(arena) else "HEAD";
if (git.Oid.parseAny(want_ref)) |oid| break :want_oid oid else |_| {}
const want_ref_head = try std.fmt.allocPrint(arena, "refs/heads/{s}", .{want_ref});
const want_ref_tag = try std.fmt.allocPrint(arena, "refs/tags/{s}", .{want_ref});
var ref_iterator: git.Session.RefIterator = undefined;
session.listRefs(&ref_iterator, .{
.ref_prefixes = &.{ want_ref, want_ref_head, want_ref_tag },
.include_peeled = true,
.buffer = reader_buffer,
}) catch |err| return f.fail(f.location_tok, try eb.printString("unable to list refs: {t}", .{err}));
defer ref_iterator.deinit();
while (ref_iterator.next() catch |err| {
return f.fail(f.location_tok, try eb.printString(
"unable to iterate refs: {s}",
.{@errorName(err)},
));
}) |ref| {
if (std.mem.eql(u8, ref.name, want_ref) or
std.mem.eql(u8, ref.name, want_ref_head) or
std.mem.eql(u8, ref.name, want_ref_tag))
{
break :want_oid ref.peeled orelse ref.oid;
}
}
return f.fail(f.location_tok, try eb.printString("ref not found: {s}", .{want_ref}));
};
if (f.use_latest_commit) {
f.latest_commit = want_oid;
} else if (uri.fragment == null) {
const notes_len = 1;
try eb.addRootErrorMessage(.{
.msg = try eb.addString("url field is missing an explicit ref"),
.src_loc = try f.srcLoc(f.location_tok),
.notes_len = notes_len,
});
const notes_start = try eb.reserveNotes(notes_len);
eb.extra.items[notes_start] = @backingInt(try eb.addErrorMessage(.{
.msg = try eb.printString("try .url = \"{f}#{f}\",", .{
uri.fmt(.{ .scheme = true, .authority = true, .path = true }),
want_oid,
}),
}));
return error.FetchFailed;
}
var want_oid_buf: [git.Oid.max_formatted_length]u8 = undefined;
_ = std.fmt.bufPrint(&want_oid_buf, "{f}", .{want_oid}) catch unreachable;
resource.* = .{ .git = .{
.session = session,
.fetch_stream = undefined,
.want_oid = want_oid,
} };
const fetch_stream = &resource.git.fetch_stream;
session.fetch(fetch_stream, &.{&want_oid_buf}, reader_buffer) catch |err| {
return f.fail(f.location_tok, try eb.printString("unable to create fetch stream: {t}", .{err}));
};
errdefer fetch_stream.deinit(fetch_stream);
return;
}
return f.fail(f.location_tok, try eb.printString("unsupported URL scheme: {s}", .{uri.scheme}));
}