╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ try.zig ──────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
126 .{ .user_index = 7, .name = "nodejs", .description = "Node.js JavaScript runtime" }, 127 .{ .user_index = 8, .name = "cpython", .description = "The Python programming language" }, 128 .{ .user_index = 9, .name = "docker", .description = "Container platform for developing, shipping, and running applications" }, 129 .{ .user_index = 0, .name = "vim", .description = "The ubiquitous text editor" }, 130 .{ .user_index = 1, .name = "neovim", .description = "Hyperextensible Vim-based text editor" }, 131 .{ .user_index = 2, .name = "emacs", .description = "GNU Emacs source code mirror" }, 132 .{ .user_index = 3, .name = "tmux", .description = "Terminal multiplexer" }, 133 .{ .user_index = 4, .name = "zsh", .description = "Mirror of the Z shell source code repository" }, 134 .{ .user_index = 5, .name = "git", .description = "Distributed version control system" }, 135 .{ .user_index = 6, .name = "mercurial", .description = "Source-control management tool" }, 136 .{ .user_index = 7, .name = "tensorflow", .description = "An end-to-end open source machine learning platform" }, 137 .{ .user_index = 8, .name = "pytorch", .description = "Tensors and dynamic neural networks in Python with strong GPU acceleration" }, 138 .{ .user_index = 9, .name = "numpy", .description = "The fundamental package for scientific computing with Python" }, 139 .{ .user_index = 0, .name = "pandas", .description = "Flexible and powerful data analysis and manipulation library for Python" }, 140 .{ .user_index = 1, .name = "scikit-learn", .description = "Machine learning in Python" }, 141 .{ .user_index = 2, .name = "nginx", .description = "High performance HTTP server and reverse proxy" }, 142 .{ .user_index = 3, .name = "redis", .description = "In-memory data structure store, used as a database, cache, and message broker" }, 143 .{ .user_index = 4, .name = "postgres", .description = "The world's most advanced open source relational database" }, 144 .{ .user_index = 5, .name = "sqlite", .description = "Self-contained, serverless, zero-configuration SQL database engine" }, 145 .{ .user_index = 6, .name = "mongodb", .description = "The MongoDB Database" }, 146 .{ .user_index = 7, .name = "elasticsearch", .description = "Free and open, distributed, RESTful search engine" }, 147 .{ .user_index = 8, .name = "kafka", .description = "Distributed event streaming platform" }, 148 .{ .user_index = 9, .name = "terraform", .description = "Infrastructure as code tool" }, 149 .{ .user_index = 10, .name = "svelte", .description = "Cybernetically enhanced web apps" }, 150 .{ .user_index = 11, .name = "vue", .description = "The progressive JavaScript framework" }, 151 .{ .user_index = 12, .name = "flask", .description = "The Python micro framework for building web applications" }, 152 .{ .user_index = 13, .name = "django", .description = "The web framework for perfectionists with deadlines" }, 153 .{ .user_index = 14, .name = "rails", .description = "Ruby on Rails web framework" }, 154 .{ .user_index = 15, .name = "phoenix", .description = "Peace of mind from prototype to production for Elixir web apps" }, 155 .{ .user_index = 16, .name = "laravel", .description = "The PHP framework for web artisans" }, 156 .{ .user_index = 17, .name = "prometheus", .description = "The Prometheus monitoring system and time series database" }, 157 .{ .user_index = 18, .name = "grafana", .description = "The open and composable observability and data visualization platform" }, 158 .{ .user_index = 19, .name = "ansible", .description = "Simple, agentless IT automation" }, 159 }; 160 161 var user_ids: [user_data.len][evt.event_id_size]u8 = undefined; 162 for (&user_ids) |*id| id.* = evt.EventWithId.randomId(prng.random()); 163 164 var repo_event_ids: [repo_data.len][evt.event_id_size]u8 = undefined; 165 for (&repo_event_ids) |*id| id.* = evt.EventWithId.randomId(prng.random()); 166 167 var password_hash_buf: [evt.User.password_hash_max_len]u8 = undefined; 168 const password_hash = try evt.User.hashPassword("password", &password_hash_buf, io); 169 170 // public key matching temp-try/key, given to admin so we can push as admin 171 const admin_ssh_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKeIs8mJqigBZ5y84J4COgnAJJ5bHPKy+lM2SliMXbYm radar@roark"; 172 173 var events_to_consume: [user_data.len + repo_data.len]evt.EventWithId = undefined; 174 for (user_data, 0..) |u, i| { 175 events_to_consume[i] = .{ 176 .id = std.fmt.bytesToHex(user_ids[i], .lower), 177 .event = .{ 178 .user = .{ 179 .name = u.name, 180 .display_name = u.display_name, 181 .email = u.email, 182 .password_hash = password_hash, 183 .ssh_keys = if (i == 0) admin_ssh_key else "", 184 }, 185 }, 186 }; 187 } 188 for (repo_data, 0..) |r, i| { 189 events_to_consume[user_data.len + i] = .{ 190 .id = std.fmt.bytesToHex(repo_event_ids[i], .lower), 191 .event = .{ 192 .repo = .{ 193 .user_id = &user_ids[r.user_index], 194 .name = r.name, 195 .description = r.description, 196 .enable_issue = true, 197 }, 198 }, 199 }; 200 } 201 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); 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" }); 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 218 { 219 var repo_dir = try cwd.openDir(io, repo_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); 226 227 try repo_dir.createDirPath(io, "docs/dev"); 228 const doc = try repo_dir.createFile(io, "docs/dev/contribute.md", .{}); 229 defer doc.close(io); 230 try doc.writeStreamingAll(io, "To contribute, please make a pull request"); 231 } 232 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" }); 235 236 // a batch of commits so the commits tab has more than one page to 237 // paginate through. each rewrites a few files with scattered line 238 // edits, so every commit is a multi-file diff with several separate 239 // hunks to look at. stepped timestamps vary the date column. 240 const base_ts: u64 = 1_700_000_000; // 2023-11-14 241 const edit_files = [_][]const u8{ "src/alpha.txt", "src/beta.txt", "src/gamma.txt" }; 242 var c: usize = 0; 243 while (c < 30) : (c += 1) { 244 { 245 var repo_dir = try cwd.openDir(io, repo_path, .{}); 246 defer repo_dir.close(io); 247 try repo_dir.createDirPath(io, "src"); 248 for (edit_files, 0..) |path, fi| { 249 const file = try repo_dir.createFile(io, path, .{}); 250 defer file.close(io); 251 var writer = std.Io.Writer.Allocating.init(allocator); 252 defer writer.deinit(); 253 // every 8th line (offset per file) encodes the commit 254 // number; the rest stay constant. the changed lines sit 255 // far enough apart that diff renders each as its own hunk. 256 for (0..40) |line| { 257 if ((line + fi) % 8 == 0) { 258 try writer.writer.print("line {d}: rev {d}\n", .{ line, c }); 259 } else { 260 try writer.writer.print("line {d}\n", .{line}); 261 } 262 } 263 try file.writeStreamingAll(io, writer.written()); 264 } 265 } 266 try repo_i.add(io, allocator, &edit_files); 267 const message = try std.fmt.allocPrint(arena.allocator(), "scattered edits {d}", .{c + 1}); 268 _ = try repo_i.commit(io, allocator, .{ .message = message, .timestamp = base_ts + c * std.time.s_per_day }); 269 } 270 } 271 272 break :blk try ui.Session.init(&session_arena, &repo, .{}); 273 }; 274 session.is_terminal = true; 275 276 // start the server 277 278 var cli = false; 279 280 var arg_it = try init.minimal.args.iterateAllocator(allocator); 281 defer arg_it.deinit(); 282 _ = arg_it.skip(); 283 while (arg_it.next()) |arg| { 284 if (std.mem.eql(u8, "--cli", arg)) { 285 cli = true; 286 } 287 } 288 289 const server_path = try std.fs.path.join(allocator, &.{ cwd_path, temp_dir_name, "server" }); 290 defer allocator.free(server_path); 291 292 // let the native TUI's page builders open the on-disk repos for the file tree 293 session.io = io; 294 session.repos_dir = try std.fs.path.join(session_arena.allocator(), &.{ server_path, "repos" }); 295 296 if (cli) { 297 var stdout_writer = std.Io.File.stdout().writer(io, &.{}); 298 var stderr_writer = std.Io.File.stderr().writer(io, &.{}); 299 const run_opts = hx.main.RunOpts{ .out = &stdout_writer.interface, .err = &stderr_writer.interface }; 300 301 const key_path = try std.fs.path.join(allocator, &.{ cwd_path, temp_dir_name, "key" }); 302 defer allocator.free(key_path); 303 304 const Runnable = struct { 305 io: std.Io, 306 key_path: []const u8, 307 308 pub fn run(self: @This()) !void { 309 std.debug.print( 310 \\ 311 \\connect to the TUI with: 312 \\ ssh -p 8022 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null localhost 313 \\ 314 \\create a git repo and push over SSH: 315 \\ mkdir -p temp-try/client/test 316 \\ cd temp-try/client/test 317 \\ git init 318 \\ echo "hello" > hello.txt 319 \\ git add hello.txt 320 \\ git commit -m "let there be light" 321 \\ GIT_SSH_COMMAND='ssh -p 8022 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes -i {s}' git push localhost:admin/test HEAD:master 322 \\ 323 \\to quit, press enter. 324 \\ 325 , .{self.key_path}); 326 // portable stdin read via std.Io — equivalent to the 327 // std.posix.read(STDIN_FILENO, ...) that doesn't compile 328 // on windows. 329 var buf: [1]u8 = undefined; 330 var stdin_reader = std.Io.File.stdin().reader(self.io, &buf); 331 _ = stdin_reader.interface.takeByte() catch {}; 332 } 333 }; 334 335 try srv.run(.xit, .{}, io, allocator, cwd_path, .{ 336 .data_dir = server_path, 337 }, run_opts.err, Runnable{ .io = io, .key_path = key_path }); 338 } else { 339 var null_writer = std.Io.Writer.Discarding.init(&.{}); 340 const run_opts = hx.main.RunOpts{ .out = &null_writer.writer, .err = &null_writer.writer }; 341 342 const Runnable = struct { 343 io: std.Io, 344 allocator: std.mem.Allocator, 345 session: *ui.Session, 346 347 pub fn run(self: @This()) !void { 348 // launch the TUI 349 try hx.ui.run(self.io, self.allocator, self.session); 350 } 351 }; 352 353 try srv.run(.xit, .{}, io, allocator, cwd_path, .{ 354 .data_dir = server_path, 355 }, run_opts.err, Runnable{ .io = io, .allocator = allocator, .session = &session }); 356 } 357 } 358