╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ net.zig ──────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
1452 defer cwd.deleteTree(io, temp_dir_name) catch {}; 1453 defer temp_dir.close(io); 1454 1455 // init server 1456 var server = try Server(transport_def, temp_dir_name, port).init(io, allocator); 1457 try server.start(); 1458 defer server.stop(); 1459 1460 const cwd_path = try std.process.currentPathAlloc(io, allocator); 1461 defer allocator.free(cwd_path); 1462 1463 const server_path = try std.fs.path.join(allocator, &.{ cwd_path, temp_dir_name, "repos", "server" }); 1464 defer allocator.free(server_path); 1465 1466 var server_repo = try rp.Repo(.xit, .{ .is_test = true }).init(io, allocator, .{ .path = server_path }); 1467 defer server_repo.deinit(io, allocator); 1468 1469 // add config 1470 switch (transport_def) { 1471 .file => try server_repo.addConfig(io, allocator, .{ .name = "core.bare", .value = "true" }), 1472 .wire => { 1473 try server_repo.addConfig(io, allocator, .{ .name = "core.bare", .value = "false" }); 1474 try server_repo.addConfig(io, allocator, .{ .name = "receive.denycurrentbranch", .value = "updateinstead" }); 1475 }, 1476 } 1477 try server_repo.addConfig(io, allocator, .{ .name = "http.receivepack", .value = "true" }); 1478 1479 // export server repo 1480 { 1481 const export_file = try server_repo.core.repo_dir.createFile(io, "git-daemon-export-ok", .{}); 1482 defer export_file.close(io); 1483 } 1484 1485 const client_path = try std.fs.path.join(allocator, &.{ cwd_path, temp_dir_name, "client" }); 1486 defer allocator.free(client_path); 1487 1488 var client_repo = try rp.Repo(repo_kind, .{ .is_test = true }).init(io, allocator, .{ .path = client_path }); 1489 defer client_repo.deinit(io, allocator); 1490 1491 var client_dir = try cwd.openDir(io, client_path, .{}); 1492 defer client_dir.close(io); 1493 1494 { 1495 const hello_txt = try client_repo.core.work_dir.createFile(io, "hello.txt", .{ .truncate = true }); 1496 defer hello_txt.close(io); 1497 try hello_txt.writeStreamingAll(io, "hello, world!"); 1498 try client_repo.add(io, allocator, &.{"hello.txt"}); 1499 } 1500 1501 // copy files from current repo into client dir 1502 for (&[_][]const u8{"src"}) |dir_name| { 1503 var src_repo_dir = try cwd.openDir(io, dir_name, .{ .iterate = true }); 1504 defer src_repo_dir.close(io); 1505 1506 var dest_repo_dir = try client_dir.createDirPathOpen(io, dir_name, .{}); 1507 defer dest_repo_dir.close(io); 1508 1509 try copyDir(io, src_repo_dir, dest_repo_dir); 1510 1511 try client_repo.add(io, allocator, &.{dir_name}); 1512 } 1513 1514 _ = try client_repo.commit(io, allocator, .{ .message = "let there be light" }); 1515 1516 // change the files so git will send them as delta objects 1517 for (&[_][]const u8{"src"}) |dir_name| { 1518 var dest_repo_dir = try client_dir.createDirPathOpen(io, dir_name, .{ .open_options = .{ .iterate = true } }); 1519 defer dest_repo_dir.close(io); 1520 1521 { 1522 var iter = dest_repo_dir.iterate(); 1523 while (try iter.next(io)) |entry| { 1524 switch (entry.kind) { 1525 .file => { 1526 const file = try dest_repo_dir.openFile(io, entry.name, .{ .mode = .read_write }); 1527 defer file.close(io); 1528 var writer = file.writer(io, &.{}); 1529 try writer.interface.writeAll("EDIT"); 1530 }, 1531 else => {}, 1532 } 1533 } 1534 } 1535 1536 try client_repo.add(io, allocator, &.{dir_name}); 1537 } 1538 1539 const commit2 = try client_repo.commit(io, allocator, .{ .message = "more stuff" }); 1540 1541 // add remote 1542 { 1543 if (.windows == builtin.os.tag) { 1544 std.mem.replaceScalar(u8, server_path, '\\', '/'); 1545 } 1546 const separator = if (server_path[0] == '/') "" else "/"; 1547 1548 const remote_url = switch (transport_def) { 1549 //.file => try std.fmt.allocPrint(allocator, "file://{s}{s}", .{ separator, server_path }), 1550 .file => try std.fmt.allocPrint(allocator, "../server", .{}), // relative file paths work too 1551 .wire => |wire_kind| switch (wire_kind) { 1552 .http => try std.fmt.allocPrint(allocator, "http://localhost:{}/server", .{port}), 1553 .raw => try std.fmt.allocPrint(allocator, "git://localhost:{}/server", .{port}), 1554 .ssh => try std.fmt.allocPrint(allocator, "ssh://localhost:{}{s}{s}", .{ port, separator, server_path }), 1555 }, 1556 }; 1557 defer allocator.free(remote_url); 1558 1559 try client_repo.addRemote(io, allocator, .{ .name = "origin", .value = remote_url }); 1560 try client_repo.addConfig(io, allocator, .{ .name = "branch.master.remote", .value = "origin" }); 1561 } 1562 1563 const is_ssh = switch (transport_def) { 1564 .file => false, 1565 .wire => |wire_kind| .ssh == wire_kind, 1566 }; 1567 1568 const receive_pack_command = try receivePackCommand(is_ssh, allocator, cwd_path, port); 1569 defer allocator.free(receive_pack_command); 1570 1571 if (shell_out_to_git) { 1572 const priv_key_path = try std.fs.path.join(allocator, &.{ cwd_path, temp_dir_name, "key" }); 1573 defer allocator.free(priv_key_path); 1574 const ssh_config_arg = try std.fmt.allocPrint(allocator, "core.sshCommand=ssh -o StrictHostKeyChecking=no -o IdentityFile={s}", .{priv_key_path}); 1575 defer allocator.free(ssh_config_arg); 1576 1577 // shell out to git so it will send delta objects 1578 var process = try std.process.spawn(io, .{ 1579 .argv = if (is_ssh) 1580 &.{ "git", "-c", ssh_config_arg, "push", "--receive-pack", receive_pack_command, "origin", "master" } 1581 else 1582 &.{ "git", "push", "origin", "master" }, 1583 .cwd = .{ .path = client_path }, 1584 .stdin = .ignore, 1585 .stdout = .ignore, 1586 .stderr = .ignore, 1587 }); 1588 const term = try process.wait(io); 1589 if (term != .exited or term.exited != 0) { 1590 return error.GitCommandFailed; 1591 } 1592 } else { 1593 const ssh_cmd_maybe: ?[]const u8 = if (is_ssh) blk: { 1594 const known_hosts_path = try std.fs.path.join(allocator, &.{ cwd_path, temp_dir_name, "known_hosts" }); 1595 defer allocator.free(known_hosts_path); 1596 1597 const priv_key_path = try std.fs.path.join(allocator, &.{ cwd_path, temp_dir_name, "key" }); 1598 defer allocator.free(priv_key_path); 1599 1600 break :blk try std.fmt.allocPrint(allocator, "ssh -o UserKnownHostsFile=\"{s}\" -o IdentityFile=\"{s}\"", .{ known_hosts_path, priv_key_path }); 1601 } else null; 1602 defer if (ssh_cmd_maybe) |ssh_cmd| allocator.free(ssh_cmd); 1603 1604 try client_repo.push( 1605 io, 1606 allocator, 1607 "origin", 1608 "master", 1609 false, 1610 .{ .wire = .{ .ssh = .{ 1611 .command = ssh_cmd_maybe, 1612 .receive_pack_command = receive_pack_command, 1613 } } }, 1614 ); 1615 1616 if (transport_def == .file) { 1617 // update the working dir 1618 try server_repo.restore(io, allocator, "."); 1619 } 1620 } 1621 1622 // make sure push was successful 1623 { 1624 const oid_master = (try server_repo.readRef(io, .{ .kind = .head, .name = "master" })).?; 1625 try std.testing.expectEqualStrings(&commit2, &oid_master); 1626 1627 const hello_txt = try temp_dir.openFile(io, "repos/server/hello.txt", .{}); 1628 defer hello_txt.close(io); 1629 } 1630 } 1631 1632 fn copyDir(io: std.Io, src_dir: std.Io.Dir, dest_dir: std.Io.Dir) !void { 1633 var iter = src_dir.iterate(); 1634 while (try iter.next(io)) |entry| { 1635 switch (entry.kind) { 1636 .file => try src_dir.copyFile(entry.name, dest_dir, entry.name, io, .{}), 1637 .directory => { 1638 try dest_dir.createDirPath(io, entry.name); 1639 var dest_entry_dir = try dest_dir.openDir(io, entry.name, .{ .access_sub_paths = true, .iterate = true, .follow_symlinks = false }); 1640 defer dest_entry_dir.close(io); 1641 var src_entry_dir = try src_dir.openDir(io, entry.name, .{ .access_sub_paths = true, .iterate = true, .follow_symlinks = false }); 1642 defer src_entry_dir.close(io); 1643 try copyDir(io, src_entry_dir, dest_entry_dir); 1644 }, 1645 else => {}, 1646 } 1647 } 1648 } 1649