╭ changed ─────────────╮ │src/event/PatchRev.zig│ ╰──────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭───────────────────────────────╮ │ 7 │ │ 8 base_oid: []const u8, │ │ 9 source_oid: []const u8, │ │10 +target_ref: []const u8, │ │11 message: []const u8, │ │12 │ │13 pub const Record = struct {│ ╰───────────────────────────────╯ ╭─────────────────────────────────────────╮ │15 removed: bool = false, │ │16 author_email: ?[]const u8 = null,│ │17 created_order: u64 = 0, │ │18 + event_oid: []const u8, │ │19 base_tree_oid: []const u8, │ │20 head_tree_oid: []const u8, │ │21 patch_oid: []const u8, │ ╰─────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │89 │ │90 try validateOid(hash_kind, record.event.base_oid); │ │91 try validateOid(hash_kind, record.event.source_oid); │ │92 + if (!std.mem.startsWith(u8, record.event.target_ref, "refs/heads/") or │ │93 + !xit.ref.validateName(record.event.target_ref["refs/".len..])) return error.InvalidTarget;│ │94 + try validateOid(hash_kind, record.event_oid); │ │95 try validateOid(hash_kind, record.base_tree_oid); │ │96 try validateOid(hash_kind, record.head_tree_oid); │ │97 try validateOid(hash_kind, record.patch_oid); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────╮ │ 99 if (existing_maybe) |existing| { │ │100 if (!std.mem.eql(u8, existing.event.base_oid, record.event.base_oid) or │ │101 !std.mem.eql(u8, existing.event.source_oid, record.event.source_oid) or│ │102 + !std.mem.eql(u8, existing.event.target_ref, record.event.target_ref) or│ │103 !std.mem.eql(u8, existing.event.message, record.event.message) or │ │104 !std.mem.eql(u8, existing.base_tree_oid, record.base_tree_oid) or │ │105 !std.mem.eql(u8, existing.head_tree_oid, record.head_tree_oid) or │ ╰────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────╮ │109 } │ │110 record.created_order = existing.created_order;│ │111 record.author_email = existing.author_email; │ │112 + record.event_oid = existing.event_oid; │ │113 } │ │114 │ │115 const cursor = try records.putCursor(record_key); │ ╰───────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │141 return try evt.read(Record, DB, hash_kind, arena, try DB.HashMap(.read_only).init(record_cursor)); │ │142 } │ │143 │ │144 +pub const WithId = struct { │ │145 + id: [evt.event_id_size]u8, │ │146 + record: Record, │ │147 +}; │ │148 + │ │149 +pub fn readNewest( │ │150 + comptime DB: type, │ │151 + comptime hash_kind: hash.HashKind, │ │152 + haxy_moment: DB.HashMap(.read_only), │ │153 + arena: *std.heap.ArenaAllocator, │ │154 +) !?WithId { │ │155 + const ids_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, id_set_key)) orelse return null;│ │156 + const ids = try DB.SortedSet(.read_only).init(ids_cursor); │ │157 + var iter = try ids.iteratorFromIndex(0); │ │158 + while (try iter.next()) |cursor| { │ │159 + const id = try evt.readOrderKeyId(DB, cursor); │ │160 + const record = (try readById(DB, hash_kind, haxy_moment, arena, &id)) orelse continue; │ │161 + if (!record.removed) return .{ .id = id, .record = record }; │ │162 + } │ │163 + return null; │ │164 +} │ │165 + │ │166 // derived commits referenced only by patch revision records │ │167 pub fn gcRoots( │ │168 comptime DB: type, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯