╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 962 pub const RepoSource = struct { │ │ 963 path: []const u8, │ │ 964 repo_kind: rp.RepoKind, │ │ 965 + // the user's global git config, so local mode picks up their identity and │ │ 966 + // their signing and ssh settings. null on the server paths, which must not │ │ 967 + // read whoever runs the server. │ │ 968 + global_config_path: ?[]const u8 = null, │ │ 969 + │ │ 970 + pub fn localInitOpts(self: RepoSource) rp.InitOpts { │ │ 971 + return .{ .path = self.path, .global_config_path = self.global_config_path }; │ │ 972 + } │ │ 973 }; │ │ 974 + │ │ 975 +// events created in local mode have no account behind them, so the commit │ │ 976 +// author comes from the repo's config, which the global config feeds into. │ │ 977 +pub const local_author_fallback = evt.CommitAuthor{ .name = "haxy", .email = "user@haxy" }; │ │ 978 + │ │ 979 +pub fn localAuthor( │ │ 980 + src: RepoSource, │ │ 981 + io: std.Io, │ │ 982 + allocator: std.mem.Allocator, │ │ 983 + arena: *std.heap.ArenaAllocator, │ │ 984 +) !evt.CommitAuthor { │ │ 985 + switch (src.repo_kind) { │ │ 986 + inline else => |repo_kind| { │ │ 987 + var any_repo = rp.AnyRepo(repo_kind, .{}).open(io, allocator, src.localInitOpts()) catch return local_author_fallback;│ │ 988 + defer any_repo.deinit(io, allocator); │ │ 989 │ │ 990 + switch (any_repo) { │ │ 991 + inline else => |*repo| { │ │ 992 + var config = try repo.listConfig(io, allocator); │ │ 993 + defer config.deinit(); │ │ 994 + │ │ 995 + const user = config.sections.get("user") orelse return local_author_fallback; │ │ 996 + const name = user.get("name") orelse return local_author_fallback; │ │ 997 + const email = user.get("email") orelse return local_author_fallback; │ │ 998 + return .{ │ │ 999 + .name = try arena.allocator().dupe(u8, name), │ │1000 + .email = try arena.allocator().dupe(u8, email), │ │1001 + }; │ │1002 + }, │ │1003 + } │ │1004 + }, │ │1005 + } │ │1006 +} │ │1007 + │ │1008 // per-connection mutable state. each SSH session / web session / local TUI │ │1009 // run gets its own. │ │1010 pub const Session = struct { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1118 } │ │1119 } │ │1120 │ │1080 - // the author for an event this session creates, or null when it may not │ │1081 - // create one. local mode has no accounts, so it authors anonymously. │ │1082 - pub fn eventAuthorEmail(self: *Self) !?[]const u8 { │ │1083 - if (self.data.is_local) return "user@haxy"; // TODO: try the repo's git config user.email first │ │1121 + // the commit author for an event this session creates, or null when it may │ │1122 + // not create one │ │1123 + pub fn eventAuthor(self: *Self) !?evt.CommitAuthor { │ │1124 + if (self.data.is_local) { │ │1125 + const src = self.local orelse return local_author_fallback; │ │1126 + const io = self.io orelse return local_author_fallback; │ │1127 + return try localAuthor(src, io, self.page_arena.child_allocator, self.page_arena); │ │1128 + } │ │1129 const user_id = self.data.user_id orelse return null; │ │1130 const moment = self.haxy_moment orelse return null; │ │1131 const user = (try evt.User.readById(evt.AdminDB, evt.admin_repo_opts.hash, moment, self.page_arena, user_id)) orelse return null;│ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────╮ │1087 - return user.event.email; │ │1132 + return .{ .name = user.event.name, .email = user.event.email };│ │1133 } │ │1134 │ │1135 // queue an action for the host to drain this frame. │ ╰─────────────────────────────────────────────────────────────────────────────╯