Something went wrong. Try again.
A Zig library that reads git repositories without running git, with log, show and diff output byte-identical to git's.
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586// SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie <jeff@ocjtech.us>// SPDX-License-Identifier: MIT
//! What a failed read of a repository was about, for a caller to show//! alongside the error: the object, the file, where in it, and a detail in//! git's own words where git has words for it.//!//! A function that can fail on the repository's account takes an optional//! `*Diagnostics` and fills in what it knows; fields it knows nothing//! about are left as they were, so a caller can reuse one across calls//! only if it resets it between them. Nothing here allocates, so filling//! one in cannot itself fail.
const std = @import("std");
const Id = @import("object.zig").Id;
const Diagnostics = @This();
/// The object being read, when the failure concerns one.object_id: ?Id = null,/// Where in the file, in bytes from its start, when that is known.offset: ?u64 = null,/// Where in the file, as a line counted from 1, when that is known.line: ?u32 = null,
path_buffer: [max_path_len]u8 = undefined,path_len: usize = 0,detail_buffer: [max_detail_len]u8 = undefined,detail_len: usize = 0,
/// The longest path kept; a longer one is cut short.pub const max_path_len = 4096;/// The longest detail kept; a longer one is cut short.pub const max_detail_len = 2048;
/// Empties every field.pub fn reset(d: *Diagnostics) void { d.* = .{};}
/// The file being read, as the caller named it, or null if there was none.pub fn path(d: *const Diagnostics) ?[]const u8 { if (d.path_len == 0) return null; return d.path_buffer[0..d.path_len];}
/// Records the file being read: `parts` joined with `/`.pub fn setPath(d: *Diagnostics, parts: []const []const u8) void { var w: std.Io.Writer = .fixed(&d.path_buffer); for (parts, 0..) |part, i| { if (i != 0) w.writeByte('/') catch break; w.writeAll(part) catch { w.end = w.buffer.len; break; }; } d.path_len = w.end;}
/// More about what went wrong, or an empty string.pub fn detail(d: *const Diagnostics) []const u8 { return d.detail_buffer[0..d.detail_len];}
/// Records more about what went wrong, formatted.pub fn setDetail(d: *Diagnostics, comptime fmt: []const u8, args: anytype) void { var w: std.Io.Writer = .fixed(&d.detail_buffer); w.print(fmt, args) catch { w.end = w.buffer.len; }; d.detail_len = w.end;}
test "a diagnostic keeps what it was told, cut short if need be" { var d: Diagnostics = .{}; try std.testing.expectEqual(null, d.path()); d.setPath(&.{ ".git/objects", "ab", "cdef" }); try std.testing.expectEqualStrings(".git/objects/ab/cdef", d.path().?); var long: [max_detail_len + 10]u8 = @splat('x'); d.setDetail("{s}", .{&long}); try std.testing.expectEqual(max_detail_len, d.detail().len); d.reset(); try std.testing.expectEqualStrings("", d.detail());}