╭ changed ──╮ │src/try.zig│ ╰───────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │202 // commit the seed events and consume them into the database │ │203 try evt.commitAndConsume(evt.admin_repo_opts, io, allocator, &repo, evt.events_ref, &events_to_consume); │ │204 │ │205 - // create the actual repos on disk, named by their hex-encoded event id │ │206 - for (repo_data, 0..) |r, i| { │ │207 - const repo_id = std.fmt.bytesToHex(repo_event_ids[i], .lower); │ │208 - const repo_path = try std.fs.path.join(arena.allocator(), &.{ cwd_path, temp_dir_name, "server", "repos", &repo_id });│ │209 - │ │210 - var repo_i = try rp.Repo(.xit, .{}).init(io, allocator, .{ .path = repo_path }); │ │211 - defer repo_i.deinit(io, allocator); │ │205 + // every repo gets the same generated history, so build it once into a │ │206 + // template repo and copy that to each repo's location below rather than │ │207 + // redoing the expensive commit work for every repo. │ │208 + const template_path = try std.fs.path.join(arena.allocator(), &.{ cwd_path, temp_dir_name, "template" }); │ │209 + { │ │210 + var template_repo = try rp.Repo(.xit, .{}).init(io, allocator, .{ .path = template_path }); │ │211 + defer template_repo.deinit(io, allocator); │ │212 │ │213 - try repo_i.addConfig(io, allocator, .{ .name = "user.name", .value = "haxy" }); │ │214 - try repo_i.addConfig(io, allocator, .{ .name = "user.email", .value = "admin@haxy" }); │ │213 + try template_repo.addConfig(io, allocator, .{ .name = "user.name", .value = "haxy" }); │ │214 + try template_repo.addConfig(io, allocator, .{ .name = "user.email", .value = "admin@haxy" }); │ │215 │ │216 - // write the repo's name and description into a README, plus a │ │217 - // nested doc so the file tree has a directory to descend into │ │216 + // a README plus a nested doc so the file tree has a directory to │ │217 + // descend into │ │218 { │ │219 - var repo_dir = try cwd.openDir(io, repo_path, .{}); │ │219 + var repo_dir = try cwd.openDir(io, template_path, .{}); │ │220 defer repo_dir.close(io); │ │221 │ │222 const readme = try repo_dir.createFile(io, "README.md", .{}); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │223 defer readme.close(io); │ │224 - const readme_content = try std.fmt.allocPrint(arena.allocator(), "# {s}\n\n{s}\n", .{ r.name, r.description });│ │225 - try readme.writeStreamingAll(io, readme_content); │ │224 + try readme.writeStreamingAll(io, "# Sample Repo\n\nA repository seeded with test data.\n"); │ │225 │ │226 try repo_dir.createDirPath(io, "docs/dev"); │ │227 const doc = try repo_dir.createFile(io, "docs/dev/contribute.md", .{}); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────╮ │229 try doc.writeStreamingAll(io, "To contribute, please make a pull request"); │ │230 } │ │231 │ │233 - try repo_i.add(io, allocator, &.{ "README.md", "docs/dev/contribute.md" }); │ │234 - _ = try repo_i.commit(io, allocator, .{ .message = "let there be light" }); │ │232 + try template_repo.add(io, allocator, &.{ "README.md", "docs/dev/contribute.md" });│ │233 + _ = try template_repo.commit(io, allocator, .{ .message = "let there be light" });│ │234 │ │235 // a batch of commits so the commits tab has more than one page to │ │236 // paginate through. each rewrites a few files with scattered line │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────╮ │258 var c: usize = 0; │ │259 while (c < 30) : (c += 1) { │ │260 { │ │262 - var repo_dir = try cwd.openDir(io, repo_path, .{}); │ │261 + var repo_dir = try cwd.openDir(io, template_path, .{});│ │262 defer repo_dir.close(io); │ │263 try repo_dir.createDirPath(io, "src"); │ │264 for (edit_files, 0..) |path, fi| { │ ╰────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────╮ │296 try file.writeStreamingAll(io, writer.written()); │ │297 } │ │298 } │ │300 - try repo_i.add(io, allocator, &edit_files); │ │299 + try template_repo.add(io, allocator, &edit_files); │ │300 // a cycling subject padded to a c-varying length so the commit│ │301 // list shows messages of different widths, capped at 120. │ │302 var msg_writer = std.Io.Writer.Allocating.init(allocator); │ ╰────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │311 try msg_writer.writer.print(" {s}", .{word}); │ │312 } │ │313 const message = try arena.allocator().dupe(u8, msg_writer.written()); │ │315 - _ = try repo_i.commit(io, allocator, .{ .message = message, .timestamp = base_ts + c * std.time.s_per_day }); │ │314 + _ = try template_repo.commit(io, allocator, .{ .message = message, .timestamp = base_ts + c * std.time.s_per_day }); │ │315 + } │ │316 + } │ │317 + │ │318 + // copy the template to each repo's on-disk location, named by its │ │319 + // hex-encoded event id. the template repo is deinitialized above, so its │ │320 + // db file is fully written before we copy it. │ │321 + { │ │322 + var template_dir = try cwd.openDir(io, template_path, .{ .iterate = true }); │ │323 + defer template_dir.close(io); │ │324 + │ │325 + for (repo_event_ids) |id_bytes| { │ │326 + const repo_id = std.fmt.bytesToHex(id_bytes, .lower); │ │327 + const repo_path = try std.fs.path.join(arena.allocator(), &.{ cwd_path, temp_dir_name, "server", "repos", &repo_id });│ │328 + var dest_dir = try cwd.createDirPathOpen(io, repo_path, .{}); │ │329 + defer dest_dir.close(io); │ │330 + try copyDir(io, template_dir, dest_dir); │ │331 } │ │332 } │ │333 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │418 try srv.run(.xit, .{}, io, allocator, cwd_path, .{ │ │419 .data_dir = server_path, │ │420 }, run_opts.err, Runnable{ .io = io, .allocator = allocator, .session = &session }); │ │421 + } │ │422 +} │ │423 + │ │424 +// recursively copy the contents of src_dir into dest_dir │ │425 +fn copyDir(io: std.Io, src_dir: std.Io.Dir, dest_dir: std.Io.Dir) !void { │ │426 + var iter = src_dir.iterate(); │ │427 + while (try iter.next(io)) |entry| { │ │428 + switch (entry.kind) { │ │429 + .file => try src_dir.copyFile(entry.name, dest_dir, entry.name, io, .{}), │ │430 + .directory => { │ │431 + try dest_dir.createDirPath(io, entry.name); │ │432 + var dest_entry_dir = try dest_dir.openDir(io, entry.name, .{ .access_sub_paths = true, .iterate = true, .follow_symlinks = false });│ │433 + defer dest_entry_dir.close(io); │ │434 + var src_entry_dir = try src_dir.openDir(io, entry.name, .{ .access_sub_paths = true, .iterate = true, .follow_symlinks = false }); │ │435 + defer src_entry_dir.close(io); │ │436 + try copyDir(io, src_entry_dir, dest_entry_dir); │ │437 + }, │ │438 + else => {}, │ │439 + } │ │440 } │ │441 } │ │442 │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯