╭ changed ────╮ │build.zig.zon│ ╰─────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 3 .version = "0.0.0", │ │ 4 .dependencies = .{ │ │ 5 .xit = .{ │ │ 6 - .url = "git+https://github.com/xit-vcs/xit#4ea5a2aa70b64fe8aba4a0b0e246bd24642bfe7b",│ │ 7 - .hash = "xit-0.0.0-Ub3nDGSxUAHkV15jDN8pisWuDXjI4w8xm6D2aKEParqP", │ │ 6 + .url = "git+https://github.com/xit-vcs/xit#76d5591bafdd25c1a30f60bd224bcd84fc95577d",│ │ 7 + .hash = "xit-0.0.0-Ub3nDGS9UAHche9pY_qj70UbdduOnZegBJO1PupJ0E-H", │ │ 8 }, │ │ 9 }, │ │10 .paths = .{ │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────╮ │src/event.zig│ ╰─────────────╯ ╭───────────────────────────────────────────────────────────╮ │12 pub const Discussion = @import("event/Discussion.zig");│ │13 pub const Comment = @import("event/Comment.zig"); │ │14 pub const Attachment = @import("event/Attachment.zig");│ │15 - │ │16 -pub const event_id_size: usize = 16; │ │17 - │ │18 -pub const MergePolicy = enum { │ │19 - field_conflicts, │ │20 - target_wins, │ │21 -}; │ │15 +pub const Patch = @import("event/Patch.zig"); │ │16 +pub const PatchRev = @import("event/PatchRev.zig"); │ │17 │ │18 // the most bytes an event's serialized form may hold │ │19 pub const max_event_size: usize = 100 * 1024; │ ╰───────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────╮ │21 // the branch haxy events are committed to before being consumed │ │22 pub const events_ref: rf.Ref = .{ .kind = .head, .name = "haxy/events" }; │ │23 │ │29 -// options + db type for *the admin repo* — the single event store that holds│ │30 -// users, repos, issues, etc. the functions below stay parameterized over │ │31 -// repo_opts because they also operate on individual repos in the repos dir, │ │32 -// which may use different options │ │24 +// options + db type for the admin repo │ │25 pub const admin_repo_opts: rp.RepoOpts(.xit) = .{}; │ │26 pub const AdminDB = rp.Repo(.xit, admin_repo_opts).DB; │ │27 │ ╰─────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────╮ │54 discuss, │ │55 comment, │ │56 attach, │ │57 + patchrev, │ │58 + patch, │ │59 }; │ │60 │ │61 // every logical event's kind and creation-ordered active/removed id sets│ ╰─────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────╮ │72 discuss: ?Discussion, │ │73 comment: ?Comment, │ │74 attach: ?Attachment, │ │75 + patchrev: ?PatchRev, │ │76 + patch: ?Patch, │ │77 }; │ │78 │ │83 -// a file committed alongside its event, as the one entry in that commit's tree.│ │84 -// it isn't serialized, so nothing about it reaches the commit message. │ │79 +// a file committed alongside its event │ │80 pub const Blob = struct { │ │81 name: []const u8, │ │82 size: u64, │ ╰────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────╮ │83 reader: *std.Io.Reader, │ │84 +}; │ │85 + │ │86 +// an entry in the fresh tree carried by one event commit│ │87 +pub const EventTreeEntry = union(enum) { │ │88 + blob: Blob, │ │89 + tree: struct { │ │90 + name: []const u8, │ │91 + oid: []const u8, │ │92 + }, │ │93 }; │ │94 │ │95 // who a commit is attributed to │ ╰─────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 97 name: []const u8, │ │ 98 email: []const u8, │ │ 99 }; │ │100 + │ │101 +pub const event_id_size: usize = 16; │ │102 + │ │103 +pub fn parseEventId(id: []const u8) ![event_id_size]u8 { │ │104 + var bytes: [event_id_size]u8 = undefined; │ │105 + _ = try std.fmt.hexToBytes(&bytes, id); │ │106 + if (!std.mem.eql(u8, id, &std.fmt.bytesToHex(bytes, .lower))) return error.InvalidEventId;│ │107 + return bytes; │ │108 +} │ │109 │ │110 pub const EventWithId = struct { │ │111 id: [event_id_size * 2]u8, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │112 event: Event, │ │113 timestamp: u64 = 0, // not serialized, because it comes from the commit timestamp │ │114 author: CommitAuthor, // not serialized, because it goes in the commit author line │ │102 - blob: ?Blob = null, // not serialized, because it goes in the commit tree │ │115 + tree_entries: []const EventTreeEntry = &.{}, // not serialized, because they go in the commit tree│ │116 │ │117 pub fn jsonStringify(self: EventWithId, jw: anytype) !void { │ │118 try jw.beginObject(); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │172 .attach => .{ │ │173 .attach = if (json_event.data) |value| │ │174 try std.json.parseFromValueLeaky(Attachment, arena.allocator(), value, .{ .ignore_unknown_fields = true })│ │175 + else │ │176 + null, │ │177 + }, │ │178 + .patch => .{ │ │179 + .patch = if (json_event.data) |value| │ │180 + try std.json.parseFromValueLeaky(Patch, arena.allocator(), value, .{ .ignore_unknown_fields = true }) │ │181 + else │ │182 + null, │ │183 + }, │ │184 + .patchrev => .{ │ │185 + .patchrev = if (json_event.data) |value| │ │186 + try std.json.parseFromValueLeaky(PatchRev, arena.allocator(), value, .{ .ignore_unknown_fields = true }) │ │187 else │ │188 null, │ │189 }, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────╮ │232 .discuss => .{ .discuss = null }, │ │233 .comment => .{ .comment = null }, │ │234 .attach => .{ .attach = null }, │ │235 + .patchrev => .{ .patchrev = null }, │ │236 + .patch => .{ .patch = null }, │ │237 }; │ │238 try consume(repo_kind, repo_opts, io, allocator, repo, events_ref, &.{.{│ │239 .id = std.fmt.bytesToHex(id.*, .lower), │ ╰─────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯