| ... | ... | @@ -1,6 +1,7 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const string = []const u8; |
| 3 | 3 | const top = @This(); |
| 4 | const time = @import("time"); |
| 4 | 5 | |
| 5 | 6 | // 40 is length of sha1 hash |
| 6 | 7 | pub const Id = *const [40]u8; |
| ... | ... | @@ -99,8 +100,8 @@ pub fn parseCommit(alloc: std.mem.Allocator, commitfile: string) !Commit { |
| 99 | 100 | const k = line[0..space]; |
| 100 | 101 | |
| 101 | 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, "committer")) result.committer = line[space + 1 ..]; |
| 103 | if (std.mem.eql(u8, k, "author")) result.author = try parseCommitUserAndAt(line[space + 1 ..]); |
| 104 | if (std.mem.eql(u8, k, "committer")) result.committer = try parseCommitUserAndAt(line[space + 1 ..]); |
| 104 | 105 | if (std.mem.eql(u8, k, "parent")) try parents.append(.{ .id = line[space + 1 ..][0..40] }); |
| 105 | 106 | } |
| 106 | 107 | result.parents = try parents.toOwnedSlice(); |
| ... | ... | @@ -108,13 +109,39 @@ pub fn parseCommit(alloc: std.mem.Allocator, commitfile: string) !Commit { |
| 108 | 109 | return result; |
| 109 | 110 | } |
| 110 | 111 | |
| 112 | fn 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 | |
| 111 | 132 | pub const Commit = struct { |
| 112 | 133 | tree: TreeId, |
| 113 | 134 | parents: []const CommitId, |
| 114 | | author: string, |
| 115 | | committer: string, |
| 135 | author: UserAndAt, |
| 136 | committer: UserAndAt, |
| 116 | 137 | gpgsig: string, |
| 117 | 138 | message: string, |
| 139 | |
| 140 | pub const UserAndAt = struct { |
| 141 | name: string, |
| 142 | email: string, |
| 143 | at: time.DateTime, |
| 144 | }; |
| 118 | 145 | }; |
| 119 | 146 | |
| 120 | 147 | pub fn parseTree(alloc: std.mem.Allocator, treefile: string) !Tree { |