| ... | ... | @@ -5,6 +5,7 @@ |
| 5 | 5 | //! a package. |
| 6 | 6 | |
| 7 | 7 | const std = @import("std"); |
| 8 | const Io = std.Io; |
| 8 | 9 | const mem = std.mem; |
| 9 | 10 | const testing = std.testing; |
| 10 | 11 | const Allocator = mem.Allocator; |
| ... | ... | @@ -67,8 +68,8 @@ pub const Oid = union(Format) { |
| 67 | 68 | }; |
| 68 | 69 | |
| 69 | 70 | const Hashing = union(Format) { |
| 70 | | sha1: std.Io.Writer.Hashing(Sha1), |
| 71 | | sha256: std.Io.Writer.Hashing(Sha256), |
| 71 | sha1: Io.Writer.Hashing(Sha1), |
| 72 | sha256: Io.Writer.Hashing(Sha256), |
| 72 | 73 | |
| 73 | 74 | fn init(oid_format: Format, buffer: []u8) Hashing { |
| 74 | 75 | return switch (oid_format) { |
| ... | ... | @@ -77,7 +78,7 @@ pub const Oid = union(Format) { |
| 77 | 78 | }; |
| 78 | 79 | } |
| 79 | 80 | |
| 80 | | fn writer(h: *@This()) *std.Io.Writer { |
| 81 | fn writer(h: *@This()) *Io.Writer { |
| 81 | 82 | return switch (h.*) { |
| 82 | 83 | inline else => |*inner| &inner.writer, |
| 83 | 84 | }; |
| ... | ... | @@ -100,7 +101,7 @@ pub const Oid = union(Format) { |
| 100 | 101 | }; |
| 101 | 102 | } |
| 102 | 103 | |
| 103 | | pub fn readBytes(oid_format: Format, reader: *std.Io.Reader) !Oid { |
| 104 | pub fn readBytes(oid_format: Format, reader: *Io.Reader) !Oid { |
| 104 | 105 | return switch (oid_format) { |
| 105 | 106 | inline else => |tag| @unionInit(Oid, @tagName(tag), (try reader.takeArray(tag.byteLength())).*), |
| 106 | 107 | }; |
| ... | ... | @@ -146,7 +147,7 @@ pub const Oid = union(Format) { |
| 146 | 147 | } else error.InvalidOid; |
| 147 | 148 | } |
| 148 | 149 | |
| 149 | | pub fn format(oid: Oid, writer: *std.Io.Writer) std.Io.Writer.Error!void { |
| 150 | pub fn format(oid: Oid, writer: *Io.Writer) Io.Writer.Error!void { |
| 150 | 151 | try writer.print("{x}", .{oid.slice()}); |
| 151 | 152 | } |
| 152 | 153 | |
| ... | ... | @@ -594,7 +595,7 @@ pub const Packet = union(enum) { |
| 594 | 595 | pub const max_data_length = 65516; |
| 595 | 596 | |
| 596 | 597 | /// Reads a packet in pkt-line format. |
| 597 | | fn read(reader: *std.Io.Reader) !Packet { |
| 598 | fn read(reader: *Io.Reader) !Packet { |
| 598 | 599 | const packet: Packet = try .peek(reader); |
| 599 | 600 | switch (packet) { |
| 600 | 601 | .data => |data| reader.toss(data.len), |
| ... | ... | @@ -605,7 +606,7 @@ pub const Packet = union(enum) { |
| 605 | 606 | |
| 606 | 607 | /// Consumes the header of a pkt-line packet and reads any associated data |
| 607 | 608 | /// into the reader's buffer, but does not consume the data. |
| 608 | | fn peek(reader: *std.Io.Reader) !Packet { |
| 609 | fn peek(reader: *Io.Reader) !Packet { |
| 609 | 610 | const length = std.fmt.parseUnsigned(u16, try reader.take(4), 16) catch return error.InvalidPacket; |
| 610 | 611 | switch (length) { |
| 611 | 612 | 0 => return .flush, |
| ... | ... | @@ -618,7 +619,7 @@ pub const Packet = union(enum) { |
| 618 | 619 | } |
| 619 | 620 | |
| 620 | 621 | /// Writes a packet in pkt-line format. |
| 621 | | fn write(packet: Packet, writer: *std.Io.Writer) !void { |
| 622 | fn write(packet: Packet, writer: *Io.Writer) !void { |
| 622 | 623 | switch (packet) { |
| 623 | 624 | .flush => try writer.writeAll("0000"), |
| 624 | 625 | .delimiter => try writer.writeAll("0001"), |
| ... | ... | @@ -812,7 +813,7 @@ pub const Session = struct { |
| 812 | 813 | |
| 813 | 814 | const CapabilityIterator = struct { |
| 814 | 815 | request: std.http.Client.Request, |
| 815 | | reader: *std.Io.Reader, |
| 816 | reader: *Io.Reader, |
| 816 | 817 | decompress: std.http.Decompress, |
| 817 | 818 | |
| 818 | 819 | const Capability = struct { |
| ... | ... | @@ -869,7 +870,7 @@ pub const Session = struct { |
| 869 | 870 | upload_pack_uri.query = null; |
| 870 | 871 | upload_pack_uri.fragment = null; |
| 871 | 872 | |
| 872 | | var body: std.Io.Writer = .fixed(options.buffer); |
| 873 | var body: Io.Writer = .fixed(options.buffer); |
| 873 | 874 | try Packet.write(.{ .data = "command=ls-refs\n" }, &body); |
| 874 | 875 | if (session.supports_agent) { |
| 875 | 876 | try Packet.write(.{ .data = agent_capability }, &body); |
| ... | ... | @@ -918,7 +919,7 @@ pub const Session = struct { |
| 918 | 919 | pub const RefIterator = struct { |
| 919 | 920 | format: Oid.Format, |
| 920 | 921 | request: std.http.Client.Request, |
| 921 | | reader: *std.Io.Reader, |
| 922 | reader: *Io.Reader, |
| 922 | 923 | decompress: std.http.Decompress, |
| 923 | 924 | |
| 924 | 925 | pub const Ref = struct { |
| ... | ... | @@ -986,7 +987,7 @@ pub const Session = struct { |
| 986 | 987 | upload_pack_uri.query = null; |
| 987 | 988 | upload_pack_uri.fragment = null; |
| 988 | 989 | |
| 989 | | var body: std.Io.Writer = .fixed(response_buffer); |
| 990 | var body: Io.Writer = .fixed(response_buffer); |
| 990 | 991 | try Packet.write(.{ .data = "command=fetch\n" }, &body); |
| 991 | 992 | if (session.supports_agent) { |
| 992 | 993 | try Packet.write(.{ .data = agent_capability }, &body); |
| ... | ... | @@ -1068,8 +1069,8 @@ pub const Session = struct { |
| 1068 | 1069 | |
| 1069 | 1070 | pub const FetchStream = struct { |
| 1070 | 1071 | request: std.http.Client.Request, |
| 1071 | | input: *std.Io.Reader, |
| 1072 | | reader: std.Io.Reader, |
| 1072 | input: *Io.Reader, |
| 1073 | reader: Io.Reader, |
| 1073 | 1074 | err: ?Error = null, |
| 1074 | 1075 | remaining_len: usize, |
| 1075 | 1076 | decompress: std.http.Decompress, |
| ... | ... | @@ -1094,7 +1095,7 @@ pub const Session = struct { |
| 1094 | 1095 | _, |
| 1095 | 1096 | }; |
| 1096 | 1097 | |
| 1097 | | pub fn stream(r: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize { |
| 1098 | pub fn stream(r: *Io.Reader, w: *Io.Writer, limit: Io.Limit) Io.Reader.StreamError!usize { |
| 1098 | 1099 | const fs: *FetchStream = @alignCast(@fieldParentPtr("reader", r)); |
| 1099 | 1100 | const input = fs.input; |
| 1100 | 1101 | if (fs.remaining_len == 0) { |
| ... | ... | @@ -1139,7 +1140,7 @@ const PackHeader = struct { |
| 1139 | 1140 | const signature = "PACK"; |
| 1140 | 1141 | const supported_version = 2; |
| 1141 | 1142 | |
| 1142 | | fn read(reader: *std.Io.Reader) !PackHeader { |
| 1143 | fn read(reader: *Io.Reader) !PackHeader { |
| 1143 | 1144 | const actual_signature = reader.take(4) catch |e| switch (e) { |
| 1144 | 1145 | error.EndOfStream => return error.InvalidHeader, |
| 1145 | 1146 | else => |other| return other, |
| ... | ... | @@ -1202,7 +1203,7 @@ const EntryHeader = union(Type) { |
| 1202 | 1203 | }; |
| 1203 | 1204 | } |
| 1204 | 1205 | |
| 1205 | | fn read(format: Oid.Format, reader: *std.Io.Reader) !EntryHeader { |
| 1206 | fn read(format: Oid.Format, reader: *Io.Reader) !EntryHeader { |
| 1206 | 1207 | const InitialByte = packed struct { len: u4, type: u3, has_next: bool }; |
| 1207 | 1208 | const initial: InitialByte = @bitCast(reader.takeByte() catch |e| switch (e) { |
| 1208 | 1209 | error.EndOfStream => return error.InvalidFormat, |
| ... | ... | @@ -1231,7 +1232,7 @@ const EntryHeader = union(Type) { |
| 1231 | 1232 | } |
| 1232 | 1233 | }; |
| 1233 | 1234 | |
| 1234 | | fn readOffsetVarInt(r: *std.Io.Reader) !u64 { |
| 1235 | fn readOffsetVarInt(r: *Io.Reader) !u64 { |
| 1235 | 1236 | const Byte = packed struct { value: u7, has_next: bool }; |
| 1236 | 1237 | var b: Byte = @bitCast(try r.takeByte()); |
| 1237 | 1238 | var value: u64 = b.value; |
| ... | ... | @@ -1250,7 +1251,7 @@ const IndexHeader = struct { |
| 1250 | 1251 | const supported_version = 2; |
| 1251 | 1252 | const size = 4 + 4 + @sizeOf([256]u32); |
| 1252 | 1253 | |
| 1253 | | fn read(index_header: *IndexHeader, reader: *std.Io.Reader) !void { |
| 1254 | fn read(index_header: *IndexHeader, reader: *Io.Reader) !void { |
| 1254 | 1255 | const sig = try reader.take(4); |
| 1255 | 1256 | if (!mem.eql(u8, sig, signature)) return error.InvalidHeader; |
| 1256 | 1257 | const version = try reader.takeInt(u32, .big); |
| ... | ... | @@ -1324,7 +1325,7 @@ pub fn indexPack( |
| 1324 | 1325 | } |
| 1325 | 1326 | @memset(fan_out_table[fan_out_index..], count); |
| 1326 | 1327 | |
| 1327 | | var index_hashed_writer = std.Io.Writer.hashed(&index_writer.interface, Oid.Hasher.init(format), &.{}); |
| 1328 | var index_hashed_writer = Io.Writer.hashed(&index_writer.interface, Oid.Hasher.init(format), &.{}); |
| 1328 | 1329 | const writer = &index_hashed_writer.writer; |
| 1329 | 1330 | try writer.writeAll(IndexHeader.signature); |
| 1330 | 1331 | try writer.writeInt(u32, IndexHeader.supported_version, .big); |
| ... | ... | @@ -1489,14 +1490,14 @@ fn resolveDeltaChain( |
| 1489 | 1490 | const delta_header = try EntryHeader.read(format, &pack.interface); |
| 1490 | 1491 | const delta_data = try readObjectRaw(allocator, &pack.interface, delta_header.uncompressedLength()); |
| 1491 | 1492 | defer allocator.free(delta_data); |
| 1492 | | var delta_reader: std.Io.Reader = .fixed(delta_data); |
| 1493 | var delta_reader: Io.Reader = .fixed(delta_data); |
| 1493 | 1494 | _ = try delta_reader.takeLeb128(u64); // base object size |
| 1494 | 1495 | const expanded_size = try delta_reader.takeLeb128(u64); |
| 1495 | 1496 | |
| 1496 | 1497 | const expanded_alloc_size = std.math.cast(usize, expanded_size) orelse return error.ObjectTooLarge; |
| 1497 | 1498 | const expanded_data = try allocator.alloc(u8, expanded_alloc_size); |
| 1498 | 1499 | errdefer allocator.free(expanded_data); |
| 1499 | | var expanded_delta_stream: std.Io.Writer = .fixed(expanded_data); |
| 1500 | var expanded_delta_stream: Io.Writer = .fixed(expanded_data); |
| 1500 | 1501 | try expandDelta(base_data, &delta_reader, &expanded_delta_stream); |
| 1501 | 1502 | if (expanded_delta_stream.end != expanded_size) return error.InvalidObject; |
| 1502 | 1503 | |
| ... | ... | @@ -1509,9 +1510,9 @@ fn resolveDeltaChain( |
| 1509 | 1510 | /// Reads the complete contents of an object from `reader`. This function may |
| 1510 | 1511 | /// read more bytes than required from `reader`, so the reader position after |
| 1511 | 1512 | /// returning is not reliable. |
| 1512 | | fn readObjectRaw(allocator: Allocator, reader: *std.Io.Reader, size: u64) ![]u8 { |
| 1513 | fn readObjectRaw(allocator: Allocator, reader: *Io.Reader, size: u64) ![]u8 { |
| 1513 | 1514 | const alloc_size = std.math.cast(usize, size) orelse return error.ObjectTooLarge; |
| 1514 | | var aw: std.Io.Writer.Allocating = .init(allocator); |
| 1515 | var aw: Io.Writer.Allocating = .init(allocator); |
| 1515 | 1516 | try aw.ensureTotalCapacity(alloc_size + std.compress.flate.max_window_len); |
| 1516 | 1517 | defer aw.deinit(); |
| 1517 | 1518 | var decompress: std.compress.flate.Decompress = .init(reader, .zlib, &.{}); |
| ... | ... | @@ -1523,7 +1524,7 @@ fn readObjectRaw(allocator: Allocator, reader: *std.Io.Reader, size: u64) ![]u8 |
| 1523 | 1524 | /// |
| 1524 | 1525 | /// The format of the delta data is documented in |
| 1525 | 1526 | /// [pack-format](https://git-scm.com/docs/pack-format). |
| 1526 | | fn expandDelta(base_object: []const u8, delta_reader: *std.Io.Reader, writer: *std.Io.Writer) !void { |
| 1527 | fn expandDelta(base_object: []const u8, delta_reader: *Io.Reader, writer: *Io.Writer) !void { |
| 1527 | 1528 | while (true) { |
| 1528 | 1529 | const inst: packed struct { value: u7, copy: bool } = @bitCast(delta_reader.takeByte() catch |e| switch (e) { |
| 1529 | 1530 | error.EndOfStream => return, |
| ... | ... | @@ -1576,7 +1577,7 @@ fn expandDelta(base_object: []const u8, delta_reader: *std.Io.Reader, writer: *s |
| 1576 | 1577 | /// - SHA-1: `dd582c0720819ab7130b103635bd7271b9fd4feb` |
| 1577 | 1578 | /// - SHA-256: `7f444a92bd4572ee4a28b2c63059924a9ca1829138553ef3e7c41ee159afae7a` |
| 1578 | 1579 | /// 4. `git checkout $commit` |
| 1579 | | fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void { |
| 1580 | fn runRepositoryTest(io: Io, comptime format: Oid.Format, head_commit: []const u8) !void { |
| 1580 | 1581 | const testrepo_pack = @embedFile("git/testdata/testrepo-" ++ @tagName(format) ++ ".pack"); |
| 1581 | 1582 | |
| 1582 | 1583 | var git_dir = testing.tmpDir(.{}); |
| ... | ... | @@ -1586,7 +1587,7 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void |
| 1586 | 1587 | try pack_file.writeAll(testrepo_pack); |
| 1587 | 1588 | |
| 1588 | 1589 | var pack_file_buffer: [2000]u8 = undefined; |
| 1589 | | var pack_file_reader = pack_file.reader(&pack_file_buffer); |
| 1590 | var pack_file_reader = pack_file.reader(io, &pack_file_buffer); |
| 1590 | 1591 | |
| 1591 | 1592 | var index_file = try git_dir.dir.createFile("testrepo.idx", .{ .read = true }); |
| 1592 | 1593 | defer index_file.close(); |
| ... | ... | @@ -1608,7 +1609,7 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void |
| 1608 | 1609 | try testing.expectEqualSlices(u8, testrepo_idx, index_file_data); |
| 1609 | 1610 | } |
| 1610 | 1611 | |
| 1611 | | var index_file_reader = index_file.reader(&index_file_buffer); |
| 1612 | var index_file_reader = index_file.reader(io, &index_file_buffer); |
| 1612 | 1613 | var repository: Repository = undefined; |
| 1613 | 1614 | try repository.init(testing.allocator, format, &pack_file_reader, &index_file_reader); |
| 1614 | 1615 | defer repository.deinit(); |
| ... | ... | @@ -1687,11 +1688,11 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void |
| 1687 | 1688 | const skip_checksums = true; |
| 1688 | 1689 | |
| 1689 | 1690 | test "SHA-1 packfile indexing and checkout" { |
| 1690 | | try runRepositoryTest(.sha1, "dd582c0720819ab7130b103635bd7271b9fd4feb"); |
| 1691 | try runRepositoryTest(std.testing.io, .sha1, "dd582c0720819ab7130b103635bd7271b9fd4feb"); |
| 1691 | 1692 | } |
| 1692 | 1693 | |
| 1693 | 1694 | test "SHA-256 packfile indexing and checkout" { |
| 1694 | | try runRepositoryTest(.sha256, "7f444a92bd4572ee4a28b2c63059924a9ca1829138553ef3e7c41ee159afae7a"); |
| 1695 | try runRepositoryTest(std.testing.io, .sha256, "7f444a92bd4572ee4a28b2c63059924a9ca1829138553ef3e7c41ee159afae7a"); |
| 1695 | 1696 | } |
| 1696 | 1697 | |
| 1697 | 1698 | /// Checks out a commit of a packfile. Intended for experimenting with and |
| ... | ... | @@ -1699,6 +1700,10 @@ test "SHA-256 packfile indexing and checkout" { |
| 1699 | 1700 | pub fn main() !void { |
| 1700 | 1701 | const allocator = std.heap.smp_allocator; |
| 1701 | 1702 | |
| 1703 | var threaded: Io.Threaded = .init(allocator); |
| 1704 | defer threaded.deinit(); |
| 1705 | const io = threaded.io(); |
| 1706 | |
| 1702 | 1707 | const args = try std.process.argsAlloc(allocator); |
| 1703 | 1708 | defer std.process.argsFree(allocator, args); |
| 1704 | 1709 | if (args.len != 5) { |
| ... | ... | @@ -1710,7 +1715,7 @@ pub fn main() !void { |
| 1710 | 1715 | var pack_file = try std.fs.cwd().openFile(args[2], .{}); |
| 1711 | 1716 | defer pack_file.close(); |
| 1712 | 1717 | var pack_file_buffer: [4096]u8 = undefined; |
| 1713 | | var pack_file_reader = pack_file.reader(&pack_file_buffer); |
| 1718 | var pack_file_reader = pack_file.reader(io, &pack_file_buffer); |
| 1714 | 1719 | |
| 1715 | 1720 | const commit = try Oid.parse(format, args[3]); |
| 1716 | 1721 | var worktree = try std.fs.cwd().makeOpenPath(args[4], .{}); |
| ... | ... | @@ -1727,7 +1732,7 @@ pub fn main() !void { |
| 1727 | 1732 | try indexPack(allocator, format, &pack_file_reader, &index_file_writer); |
| 1728 | 1733 | |
| 1729 | 1734 | std.debug.print("Starting checkout...\n", .{}); |
| 1730 | | var index_file_reader = index_file.reader(&index_file_buffer); |
| 1735 | var index_file_reader = index_file.reader(io, &index_file_buffer); |
| 1731 | 1736 | var repository: Repository = undefined; |
| 1732 | 1737 | try repository.init(allocator, format, &pack_file_reader, &index_file_reader); |
| 1733 | 1738 | defer repository.deinit(); |