╭ changed ────╮ │src/event.zig│ ╰─────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │58 return try rp.Repo(.xit, user_repo_opts).init(io, allocator, .{ .bare = true, .path = path }); │ │59 } │ │60 │ │61 -// a user repo's path, a sibling of the repos dir │ │62 -pub fn userRepoPath(allocator: std.mem.Allocator, repo_root_path: []const u8, user_id: *const [event_id_size]u8) ![]u8 { │ │63 - return try std.fs.path.join(allocator, &.{ std.fs.path.dirname(repo_root_path) orelse ".", "users", &std.fmt.bytesToHex(user_id.*, .lower) }); │ │61 +// a user repo's path, inside the user's dir │ │62 +pub fn userRepoPath(allocator: std.mem.Allocator, users_dir: []const u8, user_id: *const [event_id_size]u8) ![]u8 { │ │63 + return try std.fs.path.join(allocator, &.{ users_dir, &std.fmt.bytesToHex(user_id.*, .lower), "user" }); │ │64 +} │ │65 + │ │66 +// a repo's path, inside its owner's dir │ │67 +pub fn repoPath(allocator: std.mem.Allocator, users_dir: []const u8, owner_id: []const u8, repo_id: []const u8) ![]u8 { │ │68 + return try std.fs.path.join(allocator, &.{ users_dir, &std.fmt.bytesToHex(owner_id[0..event_id_size].*, .lower), "repos", &std.fmt.bytesToHex(repo_id[0..event_id_size].*, .lower) });│ │69 } │ │70 │ │71 // open a user's repo, or null when it's missing │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │67 -pub fn openUserRepo(io: std.Io, allocator: std.mem.Allocator, repo_root_path: []const u8, user_id: *const [event_id_size]u8) !?rp.Repo(.xit, user_repo_opts) {│ │68 - const path = try userRepoPath(allocator, repo_root_path, user_id); │ │72 +pub fn openUserRepo(io: std.Io, allocator: std.mem.Allocator, users_dir: []const u8, user_id: *const [event_id_size]u8) !?rp.Repo(.xit, user_repo_opts) { │ │73 + const path = try userRepoPath(allocator, users_dir, user_id); │ │74 defer allocator.free(path); │ │75 return rp.Repo(.xit, user_repo_opts).open(io, allocator, .{ .path = path, .require_repo_root = true }) catch |err| switch (err) { │ │76 error.RepoNotFound, error.FileNotFound => null, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────╮ │92 allocator: std.mem.Allocator, │ │93 arena: *std.heap.ArenaAllocator, │ │94 admin_moment: AdminDB.HashMap(.read_only),│ │90 - repo_root_path: []const u8, │ │95 + users_dir: []const u8, │ │96 owner_name: []const u8, │ │97 repo_name: []const u8, │ │98 ) !?Repo.RepoWithId { │ ╰──────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 99 const owner_id = (try User.readIdByName(AdminDB, admin_repo_opts.hash, admin_moment, owner_name)) orelse return null;│ │ 95 - var user_repo = (try openUserRepo(io, allocator, repo_root_path, &owner_id)) orelse return null; │ │100 + var user_repo = (try openUserRepo(io, allocator, users_dir, &owner_id)) orelse return null; │ │101 defer user_repo.deinit(io, allocator); │ │102 const moment = (try userMoment(&user_repo)) orelse return null; │ │103 return try Repo.readByName(UserDB, user_repo_opts.hash, moment, arena, repo_name); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────╮ │108 io: std.Io, │ │109 allocator: std.mem.Allocator, │ │110 arena: *std.heap.ArenaAllocator, │ │106 - repo_root_path: []const u8, │ │111 + users_dir: []const u8, │ │112 owner_id: *const [event_id_size]u8,│ │113 repo_id: []const u8, │ │114 ) !?Repo.Record { │ ╰────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │110 - var user_repo = (try openUserRepo(io, allocator, repo_root_path, owner_id)) orelse return null;│ │115 + var user_repo = (try openUserRepo(io, allocator, users_dir, owner_id)) orelse return null; │ │116 defer user_repo.deinit(io, allocator); │ │117 const moment = (try userMoment(&user_repo)) orelse return null; │ │118 return try Repo.readById(UserDB, user_repo_opts.hash, moment, arena, repo_id); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────╮ │123 io: std.Io, │ │124 allocator: std.mem.Allocator, │ │125 arena: *std.heap.ArenaAllocator, │ │121 - repo_root_path: []const u8, │ │126 + users_dir: []const u8, │ │127 forker_id: *const [event_id_size]u8,│ │128 fork_id: *const [event_id_size]u8, │ │129 ) !?Fork.Record { │ ╰─────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │125 - var user_repo = (try openUserRepo(io, allocator, repo_root_path, forker_id)) orelse return null;│ │130 + var user_repo = (try openUserRepo(io, allocator, users_dir, forker_id)) orelse return null; │ │131 defer user_repo.deinit(io, allocator); │ │132 const moment = (try userMoment(&user_repo)) orelse return null; │ │133 return try Fork.readById(UserDB, user_repo_opts.hash, moment, arena, fork_id); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │134 } │ │135 │ │131 -// the user who forked a published patch, found through the patch's author │ │132 -pub const Forker = struct { │ │133 - id: [event_id_size]u8, │ │134 - name: []const u8, │ │135 -}; │ │136 - │ │137 -pub fn readForker( │ │138 - arena: *std.heap.ArenaAllocator, │ │139 - admin_moment: AdminDB.HashMap(.read_only), │ │140 - author_email: ?[]const u8, │ │141 -) !?Forker { │ │142 - const id = (try User.readIdByEmail(AdminDB, admin_repo_opts.hash, admin_moment, author_email orelse return null)) orelse return null;│ │143 - const user = (try User.readById(AdminDB, admin_repo_opts.hash, admin_moment, arena, &id)) orelse return null; │ │144 - return .{ .id = id, .name = user.event.name }; │ │145 -} │ │146 - │ │136 // the xitdb type events are stored in. it only depends on the hash kind, so │ │137 // this matches the db of any xit repo using that hash kind. │ │138 pub fn EventDB(comptime hash_kind: hash.HashKind) type { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────╮ │1719 read_access: Repo.Access = .private, │ │1720 }; │ │1721 │ │1733 -// resolve a pushed `<owner>/<repo>` to the hex event id that names its on-disk │ │1734 -// directory under the repos dir │ │1722 +// the ids that locate a repo's on-disk directory │ │1723 +pub const RepoLocation = struct { │ │1724 + owner_id: [event_id_size]u8, │ │1725 + repo_id: [event_id_size]u8, │ │1726 +}; │ │1727 + │ │1728 +// resolve a pushed `<owner>/<repo>` to the ids that locate its on-disk directory│ │1729 pub fn resolveOrCreateRepo( │ │1730 io: std.Io, │ │1731 allocator: std.mem.Allocator, │ ╰───────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯