diff --git a/src/Package/Fetch.zig b/src/Package/Fetch.zig index 08a49da30a..46be6fa069 100644 --- a/src/Package/Fetch.zig +++ b/src/Package/Fetch.zig @@ -2069,6 +2069,7 @@ test "tarball with duplicate paths" { // const gpa = std.testing.allocator; + const io = std.testing.io; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); @@ -2079,7 +2080,7 @@ test "tarball with duplicate paths" { // Run tarball fetch, expect to fail var fb: TestFetchBuilder = undefined; - var fetch = try fb.build(gpa, tmp.dir, tarball_path); + var fetch = try fb.build(gpa, io, tmp.dir, tarball_path); defer fb.deinit(); try std.testing.expectError(error.FetchFailed, fetch.run()); @@ -2101,6 +2102,7 @@ test "tarball with excluded duplicate paths" { // const gpa = std.testing.allocator; + const io = std.testing.io; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); @@ -2111,7 +2113,7 @@ test "tarball with excluded duplicate paths" { // Run tarball fetch, should succeed var fb: TestFetchBuilder = undefined; - var fetch = try fb.build(gpa, tmp.dir, tarball_path); + var fetch = try fb.build(gpa, io, tmp.dir, tarball_path); defer fb.deinit(); try fetch.run(); @@ -2145,6 +2147,8 @@ test "tarball without root folder" { // const gpa = std.testing.allocator; + const io = std.testing.io; + var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); @@ -2155,7 +2159,7 @@ test "tarball without root folder" { // Run tarball fetch, should succeed var fb: TestFetchBuilder = undefined; - var fetch = try fb.build(gpa, tmp.dir, tarball_path); + var fetch = try fb.build(gpa, io, tmp.dir, tarball_path); defer fb.deinit(); try fetch.run(); @@ -2176,6 +2180,8 @@ test "tarball without root folder" { test "set executable bit based on file content" { if (!std.fs.has_executable_bit) return error.SkipZigTest; const gpa = std.testing.allocator; + const io = std.testing.io; + var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); @@ -2194,7 +2200,7 @@ test "set executable bit based on file content" { // -rwxrwxr-x 17 executables/script var fb: TestFetchBuilder = undefined; - var fetch = try fb.build(gpa, tmp.dir, tarball_path); + var fetch = try fb.build(gpa, io, tmp.dir, tarball_path); defer fb.deinit(); try fetch.run(); @@ -2244,13 +2250,14 @@ const TestFetchBuilder = struct { fn build( self: *TestFetchBuilder, allocator: std.mem.Allocator, + io: Io, cache_parent_dir: std.fs.Dir, path_or_url: []const u8, ) !*Fetch { const cache_dir = try cache_parent_dir.makeOpenPath("zig-global-cache", .{}); try self.thread_pool.init(.{ .allocator = allocator }); - self.http_client = .{ .allocator = allocator }; + self.http_client = .{ .allocator = allocator, .io = io }; self.global_cache_directory = .{ .handle = cache_dir, .path = null }; self.job_queue = .{ @@ -2266,6 +2273,7 @@ const TestFetchBuilder = struct { self.fetch = .{ .arena = std.heap.ArenaAllocator.init(allocator), + .io = io, .location = .{ .path_or_url = path_or_url }, .location_tok = 0, .hash_tok = .none, diff --git a/src/Package/Fetch/git.zig b/src/Package/Fetch/git.zig index df0366c783..1d01b58633 100644 --- a/src/Package/Fetch/git.zig +++ b/src/Package/Fetch/git.zig @@ -5,6 +5,7 @@ //! a package. const std = @import("std"); +const Io = std.Io; const mem = std.mem; const testing = std.testing; const Allocator = mem.Allocator; @@ -67,8 +68,8 @@ pub const Oid = union(Format) { }; const Hashing = union(Format) { - sha1: std.Io.Writer.Hashing(Sha1), - sha256: std.Io.Writer.Hashing(Sha256), + sha1: Io.Writer.Hashing(Sha1), + sha256: Io.Writer.Hashing(Sha256), fn init(oid_format: Format, buffer: []u8) Hashing { return switch (oid_format) { @@ -77,7 +78,7 @@ pub const Oid = union(Format) { }; } - fn writer(h: *@This()) *std.Io.Writer { + fn writer(h: *@This()) *Io.Writer { return switch (h.*) { inline else => |*inner| &inner.writer, }; @@ -100,7 +101,7 @@ pub const Oid = union(Format) { }; } - pub fn readBytes(oid_format: Format, reader: *std.Io.Reader) !Oid { + pub fn readBytes(oid_format: Format, reader: *Io.Reader) !Oid { return switch (oid_format) { inline else => |tag| @unionInit(Oid, @tagName(tag), (try reader.takeArray(tag.byteLength())).*), }; @@ -146,7 +147,7 @@ pub const Oid = union(Format) { } else error.InvalidOid; } - pub fn format(oid: Oid, writer: *std.Io.Writer) std.Io.Writer.Error!void { + pub fn format(oid: Oid, writer: *Io.Writer) Io.Writer.Error!void { try writer.print("{x}", .{oid.slice()}); } @@ -594,7 +595,7 @@ pub const Packet = union(enum) { pub const max_data_length = 65516; /// Reads a packet in pkt-line format. - fn read(reader: *std.Io.Reader) !Packet { + fn read(reader: *Io.Reader) !Packet { const packet: Packet = try .peek(reader); switch (packet) { .data => |data| reader.toss(data.len), @@ -605,7 +606,7 @@ pub const Packet = union(enum) { /// Consumes the header of a pkt-line packet and reads any associated data /// into the reader's buffer, but does not consume the data. - fn peek(reader: *std.Io.Reader) !Packet { + fn peek(reader: *Io.Reader) !Packet { const length = std.fmt.parseUnsigned(u16, try reader.take(4), 16) catch return error.InvalidPacket; switch (length) { 0 => return .flush, @@ -618,7 +619,7 @@ pub const Packet = union(enum) { } /// Writes a packet in pkt-line format. - fn write(packet: Packet, writer: *std.Io.Writer) !void { + fn write(packet: Packet, writer: *Io.Writer) !void { switch (packet) { .flush => try writer.writeAll("0000"), .delimiter => try writer.writeAll("0001"), @@ -812,7 +813,7 @@ pub const Session = struct { const CapabilityIterator = struct { request: std.http.Client.Request, - reader: *std.Io.Reader, + reader: *Io.Reader, decompress: std.http.Decompress, const Capability = struct { @@ -869,7 +870,7 @@ pub const Session = struct { upload_pack_uri.query = null; upload_pack_uri.fragment = null; - var body: std.Io.Writer = .fixed(options.buffer); + var body: Io.Writer = .fixed(options.buffer); try Packet.write(.{ .data = "command=ls-refs\n" }, &body); if (session.supports_agent) { try Packet.write(.{ .data = agent_capability }, &body); @@ -918,7 +919,7 @@ pub const Session = struct { pub const RefIterator = struct { format: Oid.Format, request: std.http.Client.Request, - reader: *std.Io.Reader, + reader: *Io.Reader, decompress: std.http.Decompress, pub const Ref = struct { @@ -986,7 +987,7 @@ pub const Session = struct { upload_pack_uri.query = null; upload_pack_uri.fragment = null; - var body: std.Io.Writer = .fixed(response_buffer); + var body: Io.Writer = .fixed(response_buffer); try Packet.write(.{ .data = "command=fetch\n" }, &body); if (session.supports_agent) { try Packet.write(.{ .data = agent_capability }, &body); @@ -1068,8 +1069,8 @@ pub const Session = struct { pub const FetchStream = struct { request: std.http.Client.Request, - input: *std.Io.Reader, - reader: std.Io.Reader, + input: *Io.Reader, + reader: Io.Reader, err: ?Error = null, remaining_len: usize, decompress: std.http.Decompress, @@ -1094,7 +1095,7 @@ pub const Session = struct { _, }; - pub fn stream(r: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize { + pub fn stream(r: *Io.Reader, w: *Io.Writer, limit: Io.Limit) Io.Reader.StreamError!usize { const fs: *FetchStream = @alignCast(@fieldParentPtr("reader", r)); const input = fs.input; if (fs.remaining_len == 0) { @@ -1139,7 +1140,7 @@ const PackHeader = struct { const signature = "PACK"; const supported_version = 2; - fn read(reader: *std.Io.Reader) !PackHeader { + fn read(reader: *Io.Reader) !PackHeader { const actual_signature = reader.take(4) catch |e| switch (e) { error.EndOfStream => return error.InvalidHeader, else => |other| return other, @@ -1202,7 +1203,7 @@ const EntryHeader = union(Type) { }; } - fn read(format: Oid.Format, reader: *std.Io.Reader) !EntryHeader { + fn read(format: Oid.Format, reader: *Io.Reader) !EntryHeader { const InitialByte = packed struct { len: u4, type: u3, has_next: bool }; const initial: InitialByte = @bitCast(reader.takeByte() catch |e| switch (e) { error.EndOfStream => return error.InvalidFormat, @@ -1231,7 +1232,7 @@ const EntryHeader = union(Type) { } }; -fn readOffsetVarInt(r: *std.Io.Reader) !u64 { +fn readOffsetVarInt(r: *Io.Reader) !u64 { const Byte = packed struct { value: u7, has_next: bool }; var b: Byte = @bitCast(try r.takeByte()); var value: u64 = b.value; @@ -1250,7 +1251,7 @@ const IndexHeader = struct { const supported_version = 2; const size = 4 + 4 + @sizeOf([256]u32); - fn read(index_header: *IndexHeader, reader: *std.Io.Reader) !void { + fn read(index_header: *IndexHeader, reader: *Io.Reader) !void { const sig = try reader.take(4); if (!mem.eql(u8, sig, signature)) return error.InvalidHeader; const version = try reader.takeInt(u32, .big); @@ -1324,7 +1325,7 @@ pub fn indexPack( } @memset(fan_out_table[fan_out_index..], count); - var index_hashed_writer = std.Io.Writer.hashed(&index_writer.interface, Oid.Hasher.init(format), &.{}); + var index_hashed_writer = Io.Writer.hashed(&index_writer.interface, Oid.Hasher.init(format), &.{}); const writer = &index_hashed_writer.writer; try writer.writeAll(IndexHeader.signature); try writer.writeInt(u32, IndexHeader.supported_version, .big); @@ -1489,14 +1490,14 @@ fn resolveDeltaChain( const delta_header = try EntryHeader.read(format, &pack.interface); const delta_data = try readObjectRaw(allocator, &pack.interface, delta_header.uncompressedLength()); defer allocator.free(delta_data); - var delta_reader: std.Io.Reader = .fixed(delta_data); + var delta_reader: Io.Reader = .fixed(delta_data); _ = try delta_reader.takeLeb128(u64); // base object size const expanded_size = try delta_reader.takeLeb128(u64); const expanded_alloc_size = std.math.cast(usize, expanded_size) orelse return error.ObjectTooLarge; const expanded_data = try allocator.alloc(u8, expanded_alloc_size); errdefer allocator.free(expanded_data); - var expanded_delta_stream: std.Io.Writer = .fixed(expanded_data); + var expanded_delta_stream: Io.Writer = .fixed(expanded_data); try expandDelta(base_data, &delta_reader, &expanded_delta_stream); if (expanded_delta_stream.end != expanded_size) return error.InvalidObject; @@ -1509,9 +1510,9 @@ fn resolveDeltaChain( /// Reads the complete contents of an object from `reader`. This function may /// read more bytes than required from `reader`, so the reader position after /// returning is not reliable. -fn readObjectRaw(allocator: Allocator, reader: *std.Io.Reader, size: u64) ![]u8 { +fn readObjectRaw(allocator: Allocator, reader: *Io.Reader, size: u64) ![]u8 { const alloc_size = std.math.cast(usize, size) orelse return error.ObjectTooLarge; - var aw: std.Io.Writer.Allocating = .init(allocator); + var aw: Io.Writer.Allocating = .init(allocator); try aw.ensureTotalCapacity(alloc_size + std.compress.flate.max_window_len); defer aw.deinit(); var decompress: std.compress.flate.Decompress = .init(reader, .zlib, &.{}); @@ -1523,7 +1524,7 @@ fn readObjectRaw(allocator: Allocator, reader: *std.Io.Reader, size: u64) ![]u8 /// /// The format of the delta data is documented in /// [pack-format](https://git-scm.com/docs/pack-format). -fn expandDelta(base_object: []const u8, delta_reader: *std.Io.Reader, writer: *std.Io.Writer) !void { +fn expandDelta(base_object: []const u8, delta_reader: *Io.Reader, writer: *Io.Writer) !void { while (true) { const inst: packed struct { value: u7, copy: bool } = @bitCast(delta_reader.takeByte() catch |e| switch (e) { error.EndOfStream => return, @@ -1576,7 +1577,7 @@ fn expandDelta(base_object: []const u8, delta_reader: *std.Io.Reader, writer: *s /// - SHA-1: `dd582c0720819ab7130b103635bd7271b9fd4feb` /// - SHA-256: `7f444a92bd4572ee4a28b2c63059924a9ca1829138553ef3e7c41ee159afae7a` /// 4. `git checkout $commit` -fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void { +fn runRepositoryTest(io: Io, comptime format: Oid.Format, head_commit: []const u8) !void { const testrepo_pack = @embedFile("git/testdata/testrepo-" ++ @tagName(format) ++ ".pack"); var git_dir = testing.tmpDir(.{}); @@ -1586,7 +1587,7 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void try pack_file.writeAll(testrepo_pack); var pack_file_buffer: [2000]u8 = undefined; - var pack_file_reader = pack_file.reader(&pack_file_buffer); + var pack_file_reader = pack_file.reader(io, &pack_file_buffer); var index_file = try git_dir.dir.createFile("testrepo.idx", .{ .read = true }); defer index_file.close(); @@ -1608,7 +1609,7 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void try testing.expectEqualSlices(u8, testrepo_idx, index_file_data); } - var index_file_reader = index_file.reader(&index_file_buffer); + var index_file_reader = index_file.reader(io, &index_file_buffer); var repository: Repository = undefined; try repository.init(testing.allocator, format, &pack_file_reader, &index_file_reader); defer repository.deinit(); @@ -1687,11 +1688,11 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void const skip_checksums = true; test "SHA-1 packfile indexing and checkout" { - try runRepositoryTest(.sha1, "dd582c0720819ab7130b103635bd7271b9fd4feb"); + try runRepositoryTest(std.testing.io, .sha1, "dd582c0720819ab7130b103635bd7271b9fd4feb"); } test "SHA-256 packfile indexing and checkout" { - try runRepositoryTest(.sha256, "7f444a92bd4572ee4a28b2c63059924a9ca1829138553ef3e7c41ee159afae7a"); + try runRepositoryTest(std.testing.io, .sha256, "7f444a92bd4572ee4a28b2c63059924a9ca1829138553ef3e7c41ee159afae7a"); } /// Checks out a commit of a packfile. Intended for experimenting with and @@ -1699,6 +1700,10 @@ test "SHA-256 packfile indexing and checkout" { pub fn main() !void { const allocator = std.heap.smp_allocator; + var threaded: Io.Threaded = .init(allocator); + defer threaded.deinit(); + const io = threaded.io(); + const args = try std.process.argsAlloc(allocator); defer std.process.argsFree(allocator, args); if (args.len != 5) { @@ -1710,7 +1715,7 @@ pub fn main() !void { var pack_file = try std.fs.cwd().openFile(args[2], .{}); defer pack_file.close(); var pack_file_buffer: [4096]u8 = undefined; - var pack_file_reader = pack_file.reader(&pack_file_buffer); + var pack_file_reader = pack_file.reader(io, &pack_file_buffer); const commit = try Oid.parse(format, args[3]); var worktree = try std.fs.cwd().makeOpenPath(args[4], .{}); @@ -1727,7 +1732,7 @@ pub fn main() !void { try indexPack(allocator, format, &pack_file_reader, &index_file_writer); std.debug.print("Starting checkout...\n", .{}); - var index_file_reader = index_file.reader(&index_file_buffer); + var index_file_reader = index_file.reader(io, &index_file_buffer); var repository: Repository = undefined; try repository.init(allocator, format, &pack_file_reader, &index_file_reader); defer repository.deinit();