authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2023-05-03 02:50:44 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2023-05-03 02:50:44 -07:00
log63c6242d86a976e268580fd24a2a8b7455fe1512
tree7b1aa8d770e2e174d1d96f8735ab9ceae6d87547
parent0af2b218d5efc4c7a60e25ffde8a048db4b45a77

parseCommit: better parse author and committer fields since we know the format

and its not based on any user input

2 files changed, 32 insertions(+), 4 deletions(-)

git.zig+31-4
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const std = @import("std");1const std = @import("std");
2const string = []const u8;2const string = []const u8;
3const top = @This();3const top = @This();
4const time = @import("time");
45
5// 40 is length of sha1 hash6// 40 is length of sha1 hash
6pub const Id = *const [40]u8;7pub const Id = *const [40]u8;
...@@ -99,8 +100,8 @@ pub fn parseCommit(alloc: std.mem.Allocator, commitfile: string) !Commit {...@@ -99,8 +100,8 @@ pub fn parseCommit(alloc: std.mem.Allocator, commitfile: string) !Commit {
99 const k = line[0..space];100 const k = line[0..space];
100101
101 if (std.mem.eql(u8, k, "tree")) result.tree = .{ .id = line[space + 1 ..][0..40] };102 if (std.mem.eql(u8, k, "tree")) result.tree = .{ .id = line[space + 1 ..][0..40] };
102 if (std.mem.eql(u8, k, "author")) result.author = line[space + 1 ..];103 if (std.mem.eql(u8, k, "author")) result.author = try parseCommitUserAndAt(line[space + 1 ..]);
103 if (std.mem.eql(u8, k, "committer")) result.committer = line[space + 1 ..];104 if (std.mem.eql(u8, k, "committer")) result.committer = try parseCommitUserAndAt(line[space + 1 ..]);
104 if (std.mem.eql(u8, k, "parent")) try parents.append(.{ .id = line[space + 1 ..][0..40] });105 if (std.mem.eql(u8, k, "parent")) try parents.append(.{ .id = line[space + 1 ..][0..40] });
105 }106 }
106 result.parents = try parents.toOwnedSlice();107 result.parents = try parents.toOwnedSlice();
...@@ -108,13 +109,39 @@ pub fn parseCommit(alloc: std.mem.Allocator, commitfile: string) !Commit {...@@ -108,13 +109,39 @@ pub fn parseCommit(alloc: std.mem.Allocator, commitfile: string) !Commit {
108 return result;109 return result;
109}110}
110111
112fn parseCommitUserAndAt(input: string) !Commit.UserAndAt {
113 // Mitchell Hashimoto <mitchell.hashimoto@gmail.com> 1680797363 -0700
114 // first and second part is https://datatracker.ietf.org/doc/html/rfc5322#section-3.4
115 // third part is unix epoch timestamp
116 // fourth part is TZ
117 var maybe_bad_parser = std.mem.splitBackwards(u8, input, " ");
118 const tz_part = maybe_bad_parser.next() orelse return error.BadCommitTz;
119 const time_part = maybe_bad_parser.next() orelse return error.BadCommitTime;
120 const email_part = maybe_bad_parser.next() orelse return error.BadCommitEmail;
121 const name_part = maybe_bad_parser.rest();
122 _ = tz_part;
123 std.debug.assert(email_part[0] == '<');
124 std.debug.assert(email_part[email_part.len - 1] == '>');
125 return .{
126 .name = name_part,
127 .email = std.mem.trim(u8, email_part, "<>"),
128 .at = time.DateTime.initUnix(try std.fmt.parseInt(u64, time_part, 10)),
129 };
130}
131
111pub const Commit = struct {132pub const Commit = struct {
112 tree: TreeId,133 tree: TreeId,
113 parents: []const CommitId,134 parents: []const CommitId,
114 author: string,135 author: UserAndAt,
115 committer: string,136 committer: UserAndAt,
116 gpgsig: string,137 gpgsig: string,
117 message: string,138 message: string,
139
140 pub const UserAndAt = struct {
141 name: string,
142 email: string,
143 at: time.DateTime,
144 };
118};145};
119146
120pub fn parseTree(alloc: std.mem.Allocator, treefile: string) !Tree {147pub fn parseTree(alloc: std.mem.Allocator, treefile: string) !Tree {
zig.mod+1
...@@ -4,3 +4,4 @@ main: git.zig...@@ -4,3 +4,4 @@ main: git.zig
4license: MIT4license: MIT
5description: Inspect into the depths of your .git folder purely from Zig5description: Inspect into the depths of your .git folder purely from Zig
6dependencies:6dependencies:
7 - src: git https://github.com/nektro/zig-time