╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ find.zig ─────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯
267 paths: std.mem.Allocator, 268 files: rp.Repo(.xit, repo_opts).DB.SortedMap(.read_write), 269 key: *std.ArrayList(u8), 270 prefix: []const u8, 271 oid: *const [hash.hexLen(repo_opts.hash)]u8, 272 progress_ctx_maybe: ?repo_opts.ProgressCtx, 273 ) !void { 274 var object = try obj.Object(.xit, repo_opts).init(state, io, allocator, oid); 275 defer object.deinit(); 276 const tree = switch (object.content) { 277 .tree => |tree| tree, 278 else => return, 279 }; 280 for (tree.entries.keys(), tree.entries.values()) |name, *tree_entry| { 281 if (progress.cancelled(repo_opts, progress_ctx_maybe)) return error.ClientGone; 282 const path = try fs.joinPath(paths, &.{ prefix, name }); 283 if (tree_entry.isTree()) { 284 try indexTree(repo_opts, state, io, allocator, paths, files, key, path, &std.fmt.bytesToHex(tree_entry.oid, .lower), progress_ctx_maybe); 285 } else if (indexedOid(repo_opts.hash, tree_entry)) |bytes| { 286 try fileKey(allocator, key, path); 287 try files.put(key.items, .{ .bytes = bytes }); 288 progress.report(repo_opts, io, progress_ctx_maybe, .{ .complete_one = .writing_patch }); 289 } 290 } 291 } 292 293 // the tip an index entry covers, read from its key slot as hex. 294 fn readOid( 295 comptime repo_opts: rp.RepoOpts(.xit), 296 key_cursor: rp.Repo(.xit, repo_opts).DB.Cursor(.read_only), 297 ) ![hash.hexLen(repo_opts.hash)]u8 { 298 var oid: [hash.byteLen(repo_opts.hash)]u8 = undefined; 299 if ((try key_cursor.readBytes(&oid)).len != oid.len) return error.InvalidFileIndex; 300 return std.fmt.bytesToHex(oid, .lower); 301 } 302 303 // build a file's key: its lowercased basename, a separator, then its full path. 304 fn fileKey(allocator: std.mem.Allocator, key: *std.ArrayList(u8), path: []const u8) !void { 305 const slash = std.mem.lastIndexOfScalar(u8, path, '/'); 306 const base = if (slash) |i| path[i + 1 ..] else path; 307 key.clearRetainingCapacity(); 308 try key.ensureTotalCapacity(allocator, base.len + 1 + path.len); 309 for (base) |char| key.appendAssumeCapacity(std.ascii.toLower(char)); 310 key.appendAssumeCapacity(0); 311 key.appendSliceAssumeCapacity(path); 312 } 313 314 // the blob oid a tree entry is indexed under, or null for a submodule: its oid 315 // is a commit in another repo, not a file here. 316 fn indexedOid(comptime hash_kind: hash.HashKind, tree_entry: *const tr.TreeEntry(hash_kind)) ?[]const u8 { 317 if (tree_entry.mode.content.object_type == .gitlink) return null; 318 return &tree_entry.oid; 319 } 320 321 fn parseOid(comptime hash_kind: hash.HashKind, value: []const u8) ![hash.byteLen(hash_kind)]u8 { 322 const len = comptime hash.byteLen(hash_kind); 323 if (value.len != len) return error.InvalidFileIndex; 324 return value[0..len].*; 325 } 326