╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ fork.zig ─────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
141 if (head_oid_maybe) |*head_oid| { 142 try rf.write(.xit, repo_opts, state, ctx.io, patch_path, .{ .oid = head_oid }); 143 } else { 144 try bch.add(.xit, repo_opts, state, ctx.io, .{ .name = ref.name, .target = .none }); 145 } 146 try rf.replaceHead(.xit, repo_opts, state, ctx.io, .{ .ref = ref }); 147 try xit.undo.writeMessage(repo_opts, state, .{ .custom = "create fork" }); 148 } 149 }; 150 151 try fork_repo.core.db_file.lock(io, .exclusive); 152 defer fork_repo.core.db_file.unlock(io); 153 154 const history = try DB.ArrayList(.read_write).init(fork_repo.core.db.rootCursor()); 155 try history.appendContext( 156 .{ .slot = try history.getSlot(-1) }, 157 Ctx{ .core = &fork_repo.core, .io = io }, 158 ); 159 } 160 161 try fork_repo.addConfig(io, allocator, .{ .name = "core.bare", .value = "true" }); 162 try fork_repo.addConfig(io, allocator, .{ .name = "receive.denydeletes", .value = "true" }); 163 164 // create the patch event 165 try evt.consume(.fork, .xit, repo_opts, io, allocator, &fork_repo, evt.events_ref, &.{.{ 166 .id = input.id, 167 .timestamp = input.timestamp, 168 .author = input.author, 169 .event = .{ .patch = .{ 170 .title = input.title, 171 .description = input.description, 172 .tags = input.tags, 173 .target_branch = input.target_branch, 174 } }, 175 }}); 176 177 // create the fork event 178 try evt.consume(.admin, .xit, evt.admin_repo_opts, io, allocator, admin_repo, evt.events_ref, &.{.{ 179 .id = input.id, 180 .timestamp = input.timestamp, 181 .author = input.author, 182 .event = .{ .fork = .{ 183 .user_id = &input.user_id, 184 .repo_id = &input.repo_id, 185 } }, 186 }}); 187 188 return fork_path; 189 } 190 191 // tombstone first so a missing fork never remains visible 192 pub fn remove( 193 io: std.Io, 194 allocator: std.mem.Allocator, 195 repo_root_path: []const u8, 196 admin_repo: *rp.Repo(.xit, evt.admin_repo_opts), 197 id: *const [evt.event_id_size * 2]u8, 198 expected_user_id: ?*const [evt.event_id_size]u8, 199 author: evt.CommitAuthor, 200 ) !void { 201 const fork_id = try evt.parseEventId(id); 202 var arena = std.heap.ArenaAllocator.init(allocator); 203 defer arena.deinit(); 204 const moment = try evt.currentMoment(evt.admin_repo_opts, admin_repo); 205 const record = (try evt.Fork.readById(evt.AdminDB, evt.admin_repo_opts.hash, moment, &arena, &fork_id)) orelse return error.InvalidPatchDraft; 206 if (expected_user_id) |user_id| { 207 if (!std.mem.eql(u8, record.event.user_id, user_id)) return error.InvalidPatchDraft; 208 } 209 if (!record.removed) try evt.remove(.admin, .xit, evt.admin_repo_opts, io, allocator, admin_repo, &fork_id, .fork, author); 210 211 const path = try forkPath(allocator, repo_root_path, id); 212 defer allocator.free(path); 213 try std.Io.Dir.cwd().deleteTree(io, path); 214 } 215