╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ Patch.zig ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
360 allocator: std.mem.Allocator, 361 arena: *std.heap.ArenaAllocator, 362 repo: *rp.Repo(repo_kind, repo_opts), 363 id: *const [evt.event_id_size]u8, 364 live: Record, 365 resolve: Resolve, 366 ) !Self { 367 const DB = evt.EventDB(repo_opts.hash); 368 var updated = live.event; 369 if (resolve.title) |title| updated.title = title; 370 if (resolve.labels) |labels| updated.labels = labels; 371 372 var event_db_maybe: ?evt.LocalEventDB(repo_opts.hash) = if (repo_kind == .git) try evt.LocalEventDB(repo_opts.hash).openReadOnly(io, allocator, repo.core.repo_dir) else null; 373 defer if (event_db_maybe) |*event_db| event_db.deinit(io, allocator); 374 const moment = (if (event_db_maybe) |*event_db| 375 evt.currentMomentFromDb(repo_opts.hash, event_db.db) 376 else if (repo_kind == .git) 377 return updated 378 else 379 evt.currentMoment(repo_opts, repo)) catch return updated; 380 const conflicts_cursor = (try moment.getCursor(hash.hashInt(repo_opts.hash, conflicts_key))) orelse return updated; 381 const conflicts = try DB.SortedMap(.read_only).init(conflicts_cursor); 382 const conflict_cursor = (try conflicts.getCursor(&evt.orderKeyDesc(live.created_order, id))) orelse return updated; 383 const entry = try DB.HashMap(.read_only).init(conflict_cursor); 384 const fields_cursor = (try entry.getCursor(hash.hashInt(repo_opts.hash, evt.conflicted_fields_key))) orelse return updated; 385 const fields = try fields_cursor.readBytesAlloc(arena.allocator(), null); 386 const their_cursor = (try entry.getCursor(hash.hashInt(repo_opts.hash, evt.their_record_key))) orelse return updated; 387 const theirs = try evt.read(Record, DB, repo_opts.hash, arena, try DB.HashMap(.read_only).init(their_cursor)); 388 389 const original_target_branch = updated.target_branch; 390 var field_iter = std.mem.splitScalar(u8, fields, ' '); 391 while (field_iter.next()) |field| { 392 if (std.mem.eql(u8, field, "status") and fieldListed(resolve.theirs, ',', field)) updated.status = theirs.event.status; 393 if (std.mem.eql(u8, field, "revision") and fieldListed(resolve.theirs, ',', field)) updated.revision = theirs.event.revision; 394 if (std.mem.eql(u8, field, "target_branch") and fieldListed(resolve.theirs, ',', field)) updated.target_branch = theirs.event.target_branch; 395 } 396 if (!std.mem.eql(u8, original_target_branch, updated.target_branch)) updated.revision = null; 397 398 if (!fieldListed(fields, ' ', "description")) return updated; 399 var base_description: []const u8 = ""; 400 if (try entry.getCursor(hash.hashInt(repo_opts.hash, evt.base_record_key))) |base_cursor| { 401 const base = try evt.read(Record, DB, repo_opts.hash, arena, try DB.HashMap(.read_only).init(base_cursor)); 402 base_description = base.event.description; 403 } 404 const chunks = try diff3.chunks(allocator, arena, base_description, live.event.description, theirs.event.description); 405 var resolutions: std.ArrayList([]const u8) = .empty; 406 var hunk_index: usize = 0; 407 for (chunks) |chunk| { 408 if (chunk != .conflict) continue; 409 try resolutions.append(arena.allocator(), if (hunk_index < resolve.hunks.len) resolve.hunks[hunk_index] else (chunk.conflict.ours orelse "")); 410 hunk_index += 1; 411 } 412 updated.description = try diff3.assemble(arena.allocator(), chunks, resolutions.items); 413 return updated; 414 } 415 416 fn fieldListed(fields: []const u8, delimiter: u8, name: []const u8) bool { 417 var iter = std.mem.splitScalar(u8, fields, delimiter); 418 while (iter.next()) |field| { 419 if (std.mem.eql(u8, field, name)) return true; 420 } 421 return false; 422 } 423 424 fn revisionKey(allocator: std.mem.Allocator, target_branch: []const u8, oid: []const u8) ![]u8 { 425 return std.mem.concat(allocator, u8, &.{ target_branch, "\x00", oid }); 426 } 427 428 fn statusSet( 429 comptime DB: type, 430 statuses: DB.SortedMap(.read_write), 431 status: StatusKind, 432 ) !DB.SortedSet(.read_write) { 433 return DB.SortedSet(.read_write).init(try statuses.putCursor(@tagName(status))); 434 } 435 436 fn removeFromLabelSets( 437 comptime DB: type, 438 label_statuses: DB.SortedMap(.read_write), 439 labels: []const u8, 440 status: StatusKind, 441 order_key: []const u8, 442 ) !void { 443 var label_iter = labelIterator(labels); 444 while (label_iter.next()) |label| { 445 if (label.len == 0 or label.len > label_max_len) continue; 446 var key_buffer: LabelStatusKey = undefined; 447 const key = try labelStatusKey(&key_buffer, label, status); 448 const set = try DB.SortedSet(.read_write).init(try label_statuses.putCursor(key)); 449 _ = try set.remove(order_key); 450 if (0 == try set.count()) _ = try label_statuses.remove(key); 451 } 452 } 453 454 pub fn readById( 455 comptime DB: type, 456 comptime hash_kind: hash.HashKind, 457 haxy_moment: DB.HashMap(.read_only), 458 arena: *std.heap.ArenaAllocator, 459 id: *const [evt.event_id_size]u8, 460 ) !?Record { 461 const records_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, record_map_key)) orelse return null; 462 const records = try DB.HashMap(.read_only).init(records_cursor); 463 const record_cursor = try records.getCursor(hash.hashInt(hash_kind, id)) orelse return null; 464 return try evt.read(Record, DB, hash_kind, arena, try DB.HashMap(.read_only).init(record_cursor)); 465 } 466