aboutsummaryrefslogtreecommitdiff
path: root/lib/std/Build
diff options
context:
space:
mode:
authorAndrew Kelley <andrewrk@noreply.codeberg.org>2025-12-27 14:10:46 +0100
committerAndrew Kelley <andrewrk@noreply.codeberg.org>2025-12-27 14:10:46 +0100
commite55e6b5528bb2f01de242fcf32b172e244e98e74 (patch)
tree3a5eb3193d3d192c54ab0c2b7295a7f21861c27e /lib/std/Build
parentc3f2de5e519926eb0029062fe8e782a6f9df9c05 (diff)
parent60a1ba0a8f3517356fa2941462f002a7f580545b (diff)
downloadzig-e55e6b5528bb2f01de242fcf32b172e244e98e74.tar.gz
zig-e55e6b5528bb2f01de242fcf32b172e244e98e74.zip
Merge pull request 'std: migrate all `fs` APIs to `Io`' (#30232) from std.Io-fs into master
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/30232
Diffstat (limited to 'lib/std/Build')
-rw-r--r--lib/std/Build/Cache.zig231
-rw-r--r--lib/std/Build/Cache/Directory.zig14
-rw-r--r--lib/std/Build/Cache/Path.zig46
-rw-r--r--lib/std/Build/Fuzz.zig69
-rw-r--r--lib/std/Build/Step.zig58
-rw-r--r--lib/std/Build/Step/CheckFile.zig5
-rw-r--r--lib/std/Build/Step/CheckObject.zig2
-rw-r--r--lib/std/Build/Step/Compile.zig59
-rw-r--r--lib/std/Build/Step/ConfigHeader.zig13
-rw-r--r--lib/std/Build/Step/InstallArtifact.zig7
-rw-r--r--lib/std/Build/Step/InstallDir.zig11
-rw-r--r--lib/std/Build/Step/ObjCopy.zig5
-rw-r--r--lib/std/Build/Step/Options.zig57
-rw-r--r--lib/std/Build/Step/RemoveDir.zig11
-rw-r--r--lib/std/Build/Step/Run.zig250
-rw-r--r--lib/std/Build/Step/UpdateSourceFiles.zig6
-rw-r--r--lib/std/Build/Step/WriteFile.zig37
-rw-r--r--lib/std/Build/Watch.zig20
-rw-r--r--lib/std/Build/Watch/FsEvents.zig5
-rw-r--r--lib/std/Build/WebServer.zig36
20 files changed, 468 insertions, 474 deletions
diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig
index 5e8412cfcf..b384ab13ff 100644
--- a/lib/std/Build/Cache.zig
+++ b/lib/std/Build/Cache.zig
@@ -8,7 +8,6 @@ const builtin = @import("builtin");
const std = @import("std");
const Io = std.Io;
const crypto = std.crypto;
-const fs = std.fs;
const assert = std.debug.assert;
const testing = std.testing;
const mem = std.mem;
@@ -18,7 +17,7 @@ const log = std.log.scoped(.cache);
gpa: Allocator,
io: Io,
-manifest_dir: fs.Dir,
+manifest_dir: Io.Dir,
hash: HashHelper = .{},
/// This value is accessed from multiple threads, protected by mutex.
recent_problematic_timestamp: Io.Timestamp = .zero,
@@ -71,7 +70,7 @@ const PrefixedPath = struct {
fn findPrefix(cache: *const Cache, file_path: []const u8) !PrefixedPath {
const gpa = cache.gpa;
- const resolved_path = try fs.path.resolve(gpa, &.{file_path});
+ const resolved_path = try std.fs.path.resolve(gpa, &.{file_path});
errdefer gpa.free(resolved_path);
return findPrefixResolved(cache, resolved_path);
}
@@ -102,9 +101,9 @@ fn findPrefixResolved(cache: *const Cache, resolved_path: []u8) !PrefixedPath {
}
fn getPrefixSubpath(allocator: Allocator, prefix: []const u8, path: []u8) ![]u8 {
- const relative = try fs.path.relative(allocator, prefix, path);
+ const relative = try std.fs.path.relative(allocator, prefix, path);
errdefer allocator.free(relative);
- var component_iterator = fs.path.NativeComponentIterator.init(relative);
+ var component_iterator = std.fs.path.NativeComponentIterator.init(relative);
if (component_iterator.root() != null) {
return error.NotASubPath;
}
@@ -145,17 +144,17 @@ pub const File = struct {
max_file_size: ?usize,
/// Populated if the user calls `addOpenedFile`.
/// The handle is not owned here.
- handle: ?fs.File,
+ handle: ?Io.File,
stat: Stat,
bin_digest: BinDigest,
contents: ?[]const u8,
pub const Stat = struct {
- inode: fs.File.INode,
+ inode: Io.File.INode,
size: u64,
mtime: Io.Timestamp,
- pub fn fromFs(fs_stat: fs.File.Stat) Stat {
+ pub fn fromFs(fs_stat: Io.File.Stat) Stat {
return .{
.inode = fs_stat.inode,
.size = fs_stat.size,
@@ -178,7 +177,7 @@ pub const File = struct {
file.max_file_size = if (file.max_file_size) |old| @max(old, new) else new;
}
- pub fn updateHandle(file: *File, new_handle: ?fs.File) void {
+ pub fn updateHandle(file: *File, new_handle: ?Io.File) void {
const handle = new_handle orelse return;
file.handle = handle;
}
@@ -293,16 +292,16 @@ pub fn binToHex(bin_digest: BinDigest) HexDigest {
}
pub const Lock = struct {
- manifest_file: fs.File,
+ manifest_file: Io.File,
- pub fn release(lock: *Lock) void {
+ pub fn release(lock: *Lock, io: Io) void {
if (builtin.os.tag == .windows) {
// Windows does not guarantee that locks are immediately unlocked when
// the file handle is closed. See LockFileEx documentation.
- lock.manifest_file.unlock();
+ lock.manifest_file.unlock(io);
}
- lock.manifest_file.close();
+ lock.manifest_file.close(io);
lock.* = undefined;
}
};
@@ -311,7 +310,7 @@ pub const Manifest = struct {
cache: *Cache,
/// Current state for incremental hashing.
hash: HashHelper,
- manifest_file: ?fs.File,
+ manifest_file: ?Io.File,
manifest_dirty: bool,
/// Set this flag to true before calling hit() in order to indicate that
/// upon a cache hit, the code using the cache will not modify the files
@@ -332,9 +331,9 @@ pub const Manifest = struct {
pub const Diagnostic = union(enum) {
none,
- manifest_create: fs.File.OpenError,
- manifest_read: fs.File.ReadError,
- manifest_lock: fs.File.LockError,
+ manifest_create: Io.File.OpenError,
+ manifest_read: Io.File.Reader.Error,
+ manifest_lock: Io.File.LockError,
file_open: FileOp,
file_stat: FileOp,
file_read: FileOp,
@@ -393,10 +392,10 @@ pub const Manifest = struct {
}
/// Same as `addFilePath` except the file has already been opened.
- pub fn addOpenedFile(m: *Manifest, path: Path, handle: ?fs.File, max_file_size: ?usize) !usize {
+ pub fn addOpenedFile(m: *Manifest, path: Path, handle: ?Io.File, max_file_size: ?usize) !usize {
const gpa = m.cache.gpa;
try m.files.ensureUnusedCapacity(gpa, 1);
- const resolved_path = try fs.path.resolve(gpa, &.{
+ const resolved_path = try std.fs.path.resolve(gpa, &.{
path.root_dir.path orelse ".",
path.subPathOrDot(),
});
@@ -417,7 +416,7 @@ pub const Manifest = struct {
return addFileInner(self, prefixed_path, null, max_file_size);
}
- fn addFileInner(self: *Manifest, prefixed_path: PrefixedPath, handle: ?fs.File, max_file_size: ?usize) usize {
+ fn addFileInner(self: *Manifest, prefixed_path: PrefixedPath, handle: ?Io.File, max_file_size: ?usize) usize {
const gop = self.files.getOrPutAssumeCapacityAdapted(prefixed_path, FilesAdapter{});
if (gop.found_existing) {
self.cache.gpa.free(prefixed_path.sub_path);
@@ -460,7 +459,7 @@ pub const Manifest = struct {
}
}
- pub fn addDepFile(self: *Manifest, dir: fs.Dir, dep_file_sub_path: []const u8) !void {
+ pub fn addDepFile(self: *Manifest, dir: Io.Dir, dep_file_sub_path: []const u8) !void {
assert(self.manifest_file == null);
return self.addDepFileMaybePost(dir, dep_file_sub_path);
}
@@ -503,11 +502,13 @@ pub const Manifest = struct {
@memcpy(manifest_file_path[0..self.hex_digest.len], &self.hex_digest);
manifest_file_path[hex_digest_len..][0..ext.len].* = ext.*;
+ const io = self.cache.io;
+
// We'll try to open the cache with an exclusive lock, but if that would block
// and `want_shared_lock` is set, a shared lock might be sufficient, so we'll
// open with a shared lock instead.
while (true) {
- if (self.cache.manifest_dir.createFile(&manifest_file_path, .{
+ if (self.cache.manifest_dir.createFile(io, &manifest_file_path, .{
.read = true,
.truncate = false,
.lock = .exclusive,
@@ -518,7 +519,7 @@ pub const Manifest = struct {
break;
} else |err| switch (err) {
error.WouldBlock => {
- self.manifest_file = self.cache.manifest_dir.openFile(&manifest_file_path, .{
+ self.manifest_file = self.cache.manifest_dir.openFile(io, &manifest_file_path, .{
.mode = .read_write,
.lock = .shared,
}) catch |e| {
@@ -542,7 +543,7 @@ pub const Manifest = struct {
return error.CacheCheckFailed;
}
- if (self.cache.manifest_dir.createFile(&manifest_file_path, .{
+ if (self.cache.manifest_dir.createFile(io, &manifest_file_path, .{
.read = true,
.truncate = false,
.lock = .exclusive,
@@ -702,7 +703,7 @@ pub const Manifest = struct {
const file_path = iter.rest();
const stat_size = fmt.parseInt(u64, size, 10) catch return error.InvalidFormat;
- const stat_inode = fmt.parseInt(fs.File.INode, inode, 10) catch return error.InvalidFormat;
+ const stat_inode = fmt.parseInt(Io.File.INode, inode, 10) catch return error.InvalidFormat;
const stat_mtime = fmt.parseInt(i64, mtime_nsec_str, 10) catch return error.InvalidFormat;
const file_bin_digest = b: {
if (digest_str.len != hex_digest_len) return error.InvalidFormat;
@@ -758,7 +759,7 @@ pub const Manifest = struct {
const pp = cache_hash_file.prefixed_path;
const dir = self.cache.prefixes()[pp.prefix].handle;
- const this_file = dir.openFile(pp.sub_path, .{ .mode = .read_only }) catch |err| switch (err) {
+ const this_file = dir.openFile(io, pp.sub_path, .{ .mode = .read_only }) catch |err| switch (err) {
error.FileNotFound => {
// Every digest before this one has been populated successfully.
return .{ .miss = .{ .file_digests_populated = idx } };
@@ -772,9 +773,9 @@ pub const Manifest = struct {
return error.CacheCheckFailed;
},
};
- defer this_file.close();
+ defer this_file.close(io);
- const actual_stat = this_file.stat() catch |err| {
+ const actual_stat = this_file.stat(io) catch |err| {
self.diagnostic = .{ .file_stat = .{
.file_index = idx,
.err = err,
@@ -799,7 +800,7 @@ pub const Manifest = struct {
}
var actual_digest: BinDigest = undefined;
- hashFile(this_file, &actual_digest) catch |err| {
+ hashFile(io, this_file, &actual_digest) catch |err| {
self.diagnostic = .{ .file_read = .{
.file_index = idx,
.err = err,
@@ -872,17 +873,17 @@ pub const Manifest = struct {
if (man.want_refresh_timestamp) {
man.want_refresh_timestamp = false;
- var file = man.cache.manifest_dir.createFile("timestamp", .{
+ var file = man.cache.manifest_dir.createFile(io, "timestamp", .{
.read = true,
.truncate = true,
}) catch |err| switch (err) {
error.Canceled => return error.Canceled,
else => return true,
};
- defer file.close();
+ defer file.close(io);
// Save locally and also save globally (we still hold the global lock).
- const stat = file.stat() catch |err| switch (err) {
+ const stat = file.stat(io) catch |err| switch (err) {
error.Canceled => return error.Canceled,
else => return true,
};
@@ -894,19 +895,24 @@ pub const Manifest = struct {
}
fn populateFileHash(self: *Manifest, ch_file: *File) !void {
+ const io = self.cache.io;
+
if (ch_file.handle) |handle| {
return populateFileHashHandle(self, ch_file, handle);
} else {
const pp = ch_file.prefixed_path;
const dir = self.cache.prefixes()[pp.prefix].handle;
- const handle = try dir.openFile(pp.sub_path, .{});
- defer handle.close();
+ const handle = try dir.openFile(io, pp.sub_path, .{});
+ defer handle.close(io);
return populateFileHashHandle(self, ch_file, handle);
}
}
- fn populateFileHashHandle(self: *Manifest, ch_file: *File, handle: fs.File) !void {
- const actual_stat = try handle.stat();
+ fn populateFileHashHandle(self: *Manifest, ch_file: *File, io_file: Io.File) !void {
+ const io = self.cache.io;
+ const gpa = self.cache.gpa;
+
+ const actual_stat = try io_file.stat(io);
ch_file.stat = .{
.size = actual_stat.size,
.mtime = actual_stat.mtime,
@@ -920,19 +926,17 @@ pub const Manifest = struct {
}
if (ch_file.max_file_size) |max_file_size| {
- if (ch_file.stat.size > max_file_size) {
- return error.FileTooBig;
- }
+ if (ch_file.stat.size > max_file_size) return error.FileTooBig;
- const contents = try self.cache.gpa.alloc(u8, @as(usize, @intCast(ch_file.stat.size)));
- errdefer self.cache.gpa.free(contents);
+ // Hash while reading from disk, to keep the contents in the cpu
+ // cache while doing hashing.
+ const contents = try gpa.alloc(u8, @intCast(ch_file.stat.size));
+ errdefer gpa.free(contents);
- // Hash while reading from disk, to keep the contents in the cpu cache while
- // doing hashing.
var hasher = hasher_init;
var off: usize = 0;
while (true) {
- const bytes_read = try handle.pread(contents[off..], off);
+ const bytes_read = try io_file.readPositional(io, &.{contents[off..]}, off);
if (bytes_read == 0) break;
hasher.update(contents[off..][0..bytes_read]);
off += bytes_read;
@@ -941,7 +945,7 @@ pub const Manifest = struct {
ch_file.contents = contents;
} else {
- try hashFile(handle, &ch_file.bin_digest);
+ try hashFile(io, io_file, &ch_file.bin_digest);
}
self.hash.hasher.update(&ch_file.bin_digest);
@@ -1064,14 +1068,15 @@ pub const Manifest = struct {
self.hash.hasher.update(&new_file.bin_digest);
}
- pub fn addDepFilePost(self: *Manifest, dir: fs.Dir, dep_file_sub_path: []const u8) !void {
+ pub fn addDepFilePost(self: *Manifest, dir: Io.Dir, dep_file_sub_path: []const u8) !void {
assert(self.manifest_file != null);
return self.addDepFileMaybePost(dir, dep_file_sub_path);
}
- fn addDepFileMaybePost(self: *Manifest, dir: fs.Dir, dep_file_sub_path: []const u8) !void {
+ fn addDepFileMaybePost(self: *Manifest, dir: Io.Dir, dep_file_sub_path: []const u8) !void {
const gpa = self.cache.gpa;
- const dep_file_contents = try dir.readFileAlloc(dep_file_sub_path, gpa, .limited(manifest_file_size_max));
+ const io = self.cache.io;
+ const dep_file_contents = try dir.readFileAlloc(io, dep_file_sub_path, gpa, .limited(manifest_file_size_max));
defer gpa.free(dep_file_contents);
var error_buf: std.ArrayList(u8) = .empty;
@@ -1130,13 +1135,13 @@ pub const Manifest = struct {
/// lock from exclusive to shared.
pub fn writeManifest(self: *Manifest) !void {
assert(self.have_exclusive_lock);
-
+ const io = self.cache.io;
const manifest_file = self.manifest_file.?;
if (self.manifest_dirty) {
self.manifest_dirty = false;
var buffer: [4000]u8 = undefined;
- var fw = manifest_file.writer(&buffer);
+ var fw = manifest_file.writer(io, &buffer);
writeDirtyManifestToStream(self, &fw) catch |err| switch (err) {
error.WriteFailed => return fw.err.?,
else => |e| return e,
@@ -1148,7 +1153,7 @@ pub const Manifest = struct {
}
}
- fn writeDirtyManifestToStream(self: *Manifest, fw: *fs.File.Writer) !void {
+ fn writeDirtyManifestToStream(self: *Manifest, fw: *Io.File.Writer) !void {
try fw.interface.writeAll(manifest_header ++ "\n");
for (self.files.keys()) |file| {
try fw.interface.print("{d} {d} {d} {x} {d} {s}\n", .{
@@ -1165,13 +1170,11 @@ pub const Manifest = struct {
fn downgradeToSharedLock(self: *Manifest) !void {
if (!self.have_exclusive_lock) return;
+ const io = self.cache.io;
- // WASI does not currently support flock, so we bypass it here.
- // TODO: If/when flock is supported on WASI, this check should be removed.
- // See https://github.com/WebAssembly/wasi-filesystem/issues/2
- if (builtin.os.tag != .wasi or std.process.can_spawn or !builtin.single_threaded) {
+ if (std.process.can_spawn or !builtin.single_threaded) {
const manifest_file = self.manifest_file.?;
- try manifest_file.downgradeLock();
+ try manifest_file.downgradeLock(io);
}
self.have_exclusive_lock = false;
@@ -1180,16 +1183,14 @@ pub const Manifest = struct {
fn upgradeToExclusiveLock(self: *Manifest) error{CacheCheckFailed}!bool {
if (self.have_exclusive_lock) return false;
assert(self.manifest_file != null);
+ const io = self.cache.io;
- // WASI does not currently support flock, so we bypass it here.
- // TODO: If/when flock is supported on WASI, this check should be removed.
- // See https://github.com/WebAssembly/wasi-filesystem/issues/2
- if (builtin.os.tag != .wasi or std.process.can_spawn or !builtin.single_threaded) {
+ if (std.process.can_spawn or !builtin.single_threaded) {
const manifest_file = self.manifest_file.?;
// Here we intentionally have a period where the lock is released, in case there are
// other processes holding a shared lock.
- manifest_file.unlock();
- manifest_file.lock(.exclusive) catch |err| {
+ manifest_file.unlock(io);
+ manifest_file.lock(io, .exclusive) catch |err| {
self.diagnostic = .{ .manifest_lock = err };
return error.CacheCheckFailed;
};
@@ -1202,25 +1203,23 @@ pub const Manifest = struct {
/// The `Manifest` remains safe to deinit.
/// Don't forget to call `writeManifest` before this!
pub fn toOwnedLock(self: *Manifest) Lock {
- const lock: Lock = .{
- .manifest_file = self.manifest_file.?,
- };
-
- self.manifest_file = null;
- return lock;
+ defer self.manifest_file = null;
+ return .{ .manifest_file = self.manifest_file.? };
}
/// Releases the manifest file and frees any memory the Manifest was using.
/// `Manifest.hit` must be called first.
/// Don't forget to call `writeManifest` before this!
pub fn deinit(self: *Manifest) void {
+ const io = self.cache.io;
+
if (self.manifest_file) |file| {
if (builtin.os.tag == .windows) {
// See Lock.release for why this is required on Windows
- file.unlock();
+ file.unlock(io);
}
- file.close();
+ file.close(io);
}
for (self.files.keys()) |*file| {
file.deinit(self.cache.gpa);
@@ -1278,57 +1277,33 @@ pub const Manifest = struct {
}
};
-/// On operating systems that support symlinks, does a readlink. On other operating systems,
-/// uses the file contents. Windows supports symlinks but only with elevated privileges, so
-/// it is treated as not supporting symlinks.
-pub fn readSmallFile(dir: fs.Dir, sub_path: []const u8, buffer: []u8) ![]u8 {
- if (builtin.os.tag == .windows) {
- return dir.readFile(sub_path, buffer);
- } else {
- return dir.readLink(sub_path, buffer);
- }
-}
-
-/// On operating systems that support symlinks, does a symlink. On other operating systems,
-/// uses the file contents. Windows supports symlinks but only with elevated privileges, so
-/// it is treated as not supporting symlinks.
-/// `data` must be a valid UTF-8 encoded file path and 255 bytes or fewer.
-pub fn writeSmallFile(dir: fs.Dir, sub_path: []const u8, data: []const u8) !void {
- assert(data.len <= 255);
- if (builtin.os.tag == .windows) {
- return dir.writeFile(.{ .sub_path = sub_path, .data = data });
- } else {
- return dir.symLink(data, sub_path, .{});
- }
-}
-
-fn hashFile(file: fs.File, bin_digest: *[Hasher.mac_length]u8) fs.File.PReadError!void {
- var buf: [1024]u8 = undefined;
+fn hashFile(io: Io, file: Io.File, bin_digest: *[Hasher.mac_length]u8) Io.File.ReadPositionalError!void {
+ var buffer: [2048]u8 = undefined;
var hasher = hasher_init;
- var off: u64 = 0;
+ var offset: u64 = 0;
while (true) {
- const bytes_read = try file.pread(&buf, off);
- if (bytes_read == 0) break;
- hasher.update(buf[0..bytes_read]);
- off += bytes_read;
+ const n = try file.readPositional(io, &.{&buffer}, offset);
+ if (n == 0) break;
+ hasher.update(buffer[0..n]);
+ offset += n;
}
hasher.final(bin_digest);
}
// Create/Write a file, close it, then grab its stat.mtime timestamp.
-fn testGetCurrentFileTimestamp(dir: fs.Dir) !Io.Timestamp {
+fn testGetCurrentFileTimestamp(io: Io, dir: Io.Dir) !Io.Timestamp {
const test_out_file = "test-filetimestamp.tmp";
- var file = try dir.createFile(test_out_file, .{
+ var file = try dir.createFile(io, test_out_file, .{
.read = true,
.truncate = true,
});
defer {
- file.close();
- dir.deleteFile(test_out_file) catch {};
+ file.close(io);
+ dir.deleteFile(io, test_out_file) catch {};
}
- return (try file.stat()).mtime;
+ return (try file.stat(io)).mtime;
}
test "cache file and then recall it" {
@@ -1340,11 +1315,11 @@ test "cache file and then recall it" {
const temp_file = "test.txt";
const temp_manifest_dir = "temp_manifest_dir";
- try tmp.dir.writeFile(.{ .sub_path = temp_file, .data = "Hello, world!\n" });
+ try tmp.dir.writeFile(io, .{ .sub_path = temp_file, .data = "Hello, world!\n" });
// Wait for file timestamps to tick
- const initial_time = try testGetCurrentFileTimestamp(tmp.dir);
- while ((try testGetCurrentFileTimestamp(tmp.dir)).nanoseconds == initial_time.nanoseconds) {
+ const initial_time = try testGetCurrentFileTimestamp(io, tmp.dir);
+ while ((try testGetCurrentFileTimestamp(io, tmp.dir)).nanoseconds == initial_time.nanoseconds) {
try std.Io.Clock.Duration.sleep(.{ .clock = .boot, .raw = .fromNanoseconds(1) }, io);
}
@@ -1355,10 +1330,10 @@ test "cache file and then recall it" {
var cache: Cache = .{
.io = io,
.gpa = testing.allocator,
- .manifest_dir = try tmp.dir.makeOpenPath(temp_manifest_dir, .{}),
+ .manifest_dir = try tmp.dir.createDirPathOpen(io, temp_manifest_dir, .{}),
};
cache.addPrefix(.{ .path = null, .handle = tmp.dir });
- defer cache.manifest_dir.close();
+ defer cache.manifest_dir.close(io);
{
var ch = cache.obtain();
@@ -1406,11 +1381,11 @@ test "check that changing a file makes cache fail" {
const original_temp_file_contents = "Hello, world!\n";
const updated_temp_file_contents = "Hello, world; but updated!\n";
- try tmp.dir.writeFile(.{ .sub_path = temp_file, .data = original_temp_file_contents });
+ try tmp.dir.writeFile(io, .{ .sub_path = temp_file, .data = original_temp_file_contents });
// Wait for file timestamps to tick
- const initial_time = try testGetCurrentFileTimestamp(tmp.dir);
- while ((try testGetCurrentFileTimestamp(tmp.dir)).nanoseconds == initial_time.nanoseconds) {
+ const initial_time = try testGetCurrentFileTimestamp(io, tmp.dir);
+ while ((try testGetCurrentFileTimestamp(io, tmp.dir)).nanoseconds == initial_time.nanoseconds) {
try std.Io.Clock.Duration.sleep(.{ .clock = .boot, .raw = .fromNanoseconds(1) }, io);
}
@@ -1421,10 +1396,10 @@ test "check that changing a file makes cache fail" {
var cache: Cache = .{
.io = io,
.gpa = testing.allocator,
- .manifest_dir = try tmp.dir.makeOpenPath(temp_manifest_dir, .{}),
+ .manifest_dir = try tmp.dir.createDirPathOpen(io, temp_manifest_dir, .{}),
};
cache.addPrefix(.{ .path = null, .handle = tmp.dir });
- defer cache.manifest_dir.close();
+ defer cache.manifest_dir.close(io);
{
var ch = cache.obtain();
@@ -1443,7 +1418,7 @@ test "check that changing a file makes cache fail" {
try ch.writeManifest();
}
- try tmp.dir.writeFile(.{ .sub_path = temp_file, .data = updated_temp_file_contents });
+ try tmp.dir.writeFile(io, .{ .sub_path = temp_file, .data = updated_temp_file_contents });
{
var ch = cache.obtain();
@@ -1481,10 +1456,10 @@ test "no file inputs" {
var cache: Cache = .{
.io = io,
.gpa = testing.allocator,
- .manifest_dir = try tmp.dir.makeOpenPath(temp_manifest_dir, .{}),
+ .manifest_dir = try tmp.dir.createDirPathOpen(io, temp_manifest_dir, .{}),
};
cache.addPrefix(.{ .path = null, .handle = tmp.dir });
- defer cache.manifest_dir.close();
+ defer cache.manifest_dir.close(io);
{
var man = cache.obtain();
@@ -1523,12 +1498,12 @@ test "Manifest with files added after initial hash work" {
const temp_file2 = "cache_hash_post_file_test2.txt";
const temp_manifest_dir = "cache_hash_post_file_manifest_dir";
- try tmp.dir.writeFile(.{ .sub_path = temp_file1, .data = "Hello, world!\n" });
- try tmp.dir.writeFile(.{ .sub_path = temp_file2, .data = "Hello world the second!\n" });
+ try tmp.dir.writeFile(io, .{ .sub_path = temp_file1, .data = "Hello, world!\n" });
+ try tmp.dir.writeFile(io, .{ .sub_path = temp_file2, .data = "Hello world the second!\n" });
// Wait for file timestamps to tick
- const initial_time = try testGetCurrentFileTimestamp(tmp.dir);
- while ((try testGetCurrentFileTimestamp(tmp.dir)).nanoseconds == initial_time.nanoseconds) {
+ const initial_time = try testGetCurrentFileTimestamp(io, tmp.dir);
+ while ((try testGetCurrentFileTimestamp(io, tmp.dir)).nanoseconds == initial_time.nanoseconds) {
try std.Io.Clock.Duration.sleep(.{ .clock = .boot, .raw = .fromNanoseconds(1) }, io);
}
@@ -1540,10 +1515,10 @@ test "Manifest with files added after initial hash work" {
var cache: Cache = .{
.io = io,
.gpa = testing.allocator,
- .manifest_dir = try tmp.dir.makeOpenPath(temp_manifest_dir, .{}),
+ .manifest_dir = try tmp.dir.createDirPathOpen(io, temp_manifest_dir, .{}),
};
cache.addPrefix(.{ .path = null, .handle = tmp.dir });
- defer cache.manifest_dir.close();
+ defer cache.manifest_dir.close(io);
{
var ch = cache.obtain();
@@ -1575,11 +1550,11 @@ test "Manifest with files added after initial hash work" {
try testing.expect(mem.eql(u8, &digest1, &digest2));
// Modify the file added after initial hash
- try tmp.dir.writeFile(.{ .sub_path = temp_file2, .data = "Hello world the second, updated\n" });
+ try tmp.dir.writeFile(io, .{ .sub_path = temp_file2, .data = "Hello world the second, updated\n" });
// Wait for file timestamps to tick
- const initial_time2 = try testGetCurrentFileTimestamp(tmp.dir);
- while ((try testGetCurrentFileTimestamp(tmp.dir)).nanoseconds == initial_time2.nanoseconds) {
+ const initial_time2 = try testGetCurrentFileTimestamp(io, tmp.dir);
+ while ((try testGetCurrentFileTimestamp(io, tmp.dir)).nanoseconds == initial_time2.nanoseconds) {
try std.Io.Clock.Duration.sleep(.{ .clock = .boot, .raw = .fromNanoseconds(1) }, io);
}
diff --git a/lib/std/Build/Cache/Directory.zig b/lib/std/Build/Cache/Directory.zig
index a105a91ed6..ce5f5b02bb 100644
--- a/lib/std/Build/Cache/Directory.zig
+++ b/lib/std/Build/Cache/Directory.zig
@@ -1,7 +1,9 @@
const Directory = @This();
+
const std = @import("../../std.zig");
-const assert = std.debug.assert;
+const Io = std.Io;
const fs = std.fs;
+const assert = std.debug.assert;
const fmt = std.fmt;
const Allocator = std.mem.Allocator;
@@ -9,7 +11,7 @@ const Allocator = std.mem.Allocator;
/// directly, but it is needed when passing the directory to a child process.
/// `null` means cwd.
path: ?[]const u8,
-handle: fs.Dir,
+handle: Io.Dir,
pub fn clone(d: Directory, arena: Allocator) Allocator.Error!Directory {
return .{
@@ -21,7 +23,7 @@ pub fn clone(d: Directory, arena: Allocator) Allocator.Error!Directory {
pub fn cwd() Directory {
return .{
.path = null,
- .handle = fs.cwd(),
+ .handle = .cwd(),
};
}
@@ -50,8 +52,8 @@ pub fn joinZ(self: Directory, allocator: Allocator, paths: []const []const u8) !
/// Whether or not the handle should be closed, or the path should be freed
/// is determined by usage, however this function is provided for convenience
/// if it happens to be what the caller needs.
-pub fn closeAndFree(self: *Directory, gpa: Allocator) void {
- self.handle.close();
+pub fn closeAndFree(self: *Directory, gpa: Allocator, io: Io) void {
+ self.handle.close(io);
if (self.path) |p| gpa.free(p);
self.* = undefined;
}
@@ -64,5 +66,5 @@ pub fn format(self: Directory, writer: *std.Io.Writer) std.Io.Writer.Error!void
}
pub fn eql(self: Directory, other: Directory) bool {
- return self.handle.fd == other.handle.fd;
+ return self.handle.handle == other.handle.handle;
}
diff --git a/lib/std/Build/Cache/Path.zig b/lib/std/Build/Cache/Path.zig
index 92290cfdf4..2b7814c544 100644
--- a/lib/std/Build/Cache/Path.zig
+++ b/lib/std/Build/Cache/Path.zig
@@ -2,8 +2,8 @@ const Path = @This();
const std = @import("../../std.zig");
const Io = std.Io;
-const assert = std.debug.assert;
const fs = std.fs;
+const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const Cache = std.Build.Cache;
@@ -59,58 +59,56 @@ pub fn joinStringZ(p: Path, gpa: Allocator, sub_path: []const u8) Allocator.Erro
return p.root_dir.joinZ(gpa, parts);
}
-pub fn openFile(
- p: Path,
- sub_path: []const u8,
- flags: fs.File.OpenFlags,
-) !fs.File {
+pub fn openFile(p: Path, io: Io, sub_path: []const u8, flags: Io.File.OpenFlags) !Io.File {
var buf: [fs.max_path_bytes]u8 = undefined;
const joined_path = if (p.sub_path.len == 0) sub_path else p: {
break :p std.fmt.bufPrint(&buf, "{s}" ++ fs.path.sep_str ++ "{s}", .{
p.sub_path, sub_path,
}) catch return error.NameTooLong;
};
- return p.root_dir.handle.openFile(joined_path, flags);
+ return p.root_dir.handle.openFile(io, joined_path, flags);
}
pub fn openDir(
p: Path,
+ io: Io,
sub_path: []const u8,
- args: fs.Dir.OpenOptions,
-) fs.Dir.OpenError!fs.Dir {
+ args: Io.Dir.OpenOptions,
+) Io.Dir.OpenError!Io.Dir {
var buf: [fs.max_path_bytes]u8 = undefined;
const joined_path = if (p.sub_path.len == 0) sub_path else p: {
break :p std.fmt.bufPrint(&buf, "{s}" ++ fs.path.sep_str ++ "{s}", .{
p.sub_path, sub_path,
}) catch return error.NameTooLong;
};
- return p.root_dir.handle.openDir(joined_path, args);
+ return p.root_dir.handle.openDir(io, joined_path, args);
}
-pub fn makeOpenPath(p: Path, sub_path: []const u8, opts: fs.Dir.OpenOptions) !fs.Dir {
+pub fn createDirPathOpen(p: Path, io: Io, sub_path: []const u8, opts: Io.Dir.OpenOptions) !Io.Dir {
var buf: [fs.max_path_bytes]u8 = undefined;
const joined_path = if (p.sub_path.len == 0) sub_path else p: {
break :p std.fmt.bufPrint(&buf, "{s}" ++ fs.path.sep_str ++ "{s}", .{
p.sub_path, sub_path,
}) catch return error.NameTooLong;
};
- return p.root_dir.handle.makeOpenPath(joined_path, opts);
+ return p.root_dir.handle.createDirPathOpen(io, joined_path, opts);
}
-pub fn statFile(p: Path, sub_path: []const u8) !fs.Dir.Stat {
+pub fn statFile(p: Path, io: Io, sub_path: []const u8) !Io.Dir.Stat {
var buf: [fs.max_path_bytes]u8 = undefined;
const joined_path = if (p.sub_path.len == 0) sub_path else p: {
break :p std.fmt.bufPrint(&buf, "{s}" ++ fs.path.sep_str ++ "{s}", .{
p.sub_path, sub_path,
}) catch return error.NameTooLong;
};
- return p.root_dir.handle.statFile(joined_path);
+ return p.root_dir.handle.statFile(io, joined_path, .{});
}
pub fn atomicFile(
p: Path,
+ io: Io,
sub_path: []const u8,
- options: fs.Dir.AtomicFileOptions,
+ options: Io.Dir.AtomicFileOptions,
buf: *[fs.max_path_bytes]u8,
) !fs.AtomicFile {
const joined_path = if (p.sub_path.len == 0) sub_path else p: {
@@ -118,27 +116,27 @@ pub fn atomicFile(
p.sub_path, sub_path,
}) catch return error.NameTooLong;
};
- return p.root_dir.handle.atomicFile(joined_path, options);
+ return p.root_dir.handle.atomicFile(io, joined_path, options);
}
-pub fn access(p: Path, sub_path: []const u8, flags: Io.Dir.AccessOptions) !void {
+pub fn access(p: Path, io: Io, sub_path: []const u8, flags: Io.Dir.AccessOptions) !void {
var buf: [fs.max_path_bytes]u8 = undefined;
const joined_path = if (p.sub_path.len == 0) sub_path else p: {
break :p std.fmt.bufPrint(&buf, "{s}" ++ fs.path.sep_str ++ "{s}", .{
p.sub_path, sub_path,
}) catch return error.NameTooLong;
};
- return p.root_dir.handle.access(joined_path, flags);
+ return p.root_dir.handle.access(io, joined_path, flags);
}
-pub fn makePath(p: Path, sub_path: []const u8) !void {
+pub fn createDirPath(p: Path, io: Io, sub_path: []const u8) !void {
var buf: [fs.max_path_bytes]u8 = undefined;
const joined_path = if (p.sub_path.len == 0) sub_path else p: {
break :p std.fmt.bufPrint(&buf, "{s}" ++ fs.path.sep_str ++ "{s}", .{
p.sub_path, sub_path,
}) catch return error.NameTooLong;
};
- return p.root_dir.handle.makePath(joined_path);
+ return p.root_dir.handle.createDirPath(io, joined_path);
}
pub fn toString(p: Path, allocator: Allocator) Allocator.Error![]u8 {
@@ -180,7 +178,7 @@ pub fn formatEscapeChar(path: Path, writer: *Io.Writer) Io.Writer.Error!void {
}
pub fn format(self: Path, writer: *Io.Writer) Io.Writer.Error!void {
- if (std.fs.path.isAbsolute(self.sub_path)) {
+ if (fs.path.isAbsolute(self.sub_path)) {
try writer.writeAll(self.sub_path);
return;
}
@@ -225,9 +223,9 @@ pub const TableAdapter = struct {
pub fn hash(self: TableAdapter, a: Cache.Path) u32 {
_ = self;
- const seed = switch (@typeInfo(@TypeOf(a.root_dir.handle.fd))) {
- .pointer => @intFromPtr(a.root_dir.handle.fd),
- .int => @as(u32, @bitCast(a.root_dir.handle.fd)),
+ const seed = switch (@typeInfo(@TypeOf(a.root_dir.handle.handle))) {
+ .pointer => @intFromPtr(a.root_dir.handle.handle),
+ .int => @as(u32, @bitCast(a.root_dir.handle.handle)),
else => @compileError("unimplemented hash function"),
};
return @truncate(Hash.hash(seed, a.sub_path));
diff --git a/lib/std/Build/Fuzz.zig b/lib/std/Build/Fuzz.zig
index 2897b29969..d308efdf70 100644
--- a/lib/std/Build/Fuzz.zig
+++ b/lib/std/Build/Fuzz.zig
@@ -9,14 +9,12 @@ const Allocator = std.mem.Allocator;
const log = std.log;
const Coverage = std.debug.Coverage;
const abi = Build.abi.fuzz;
-const tty = std.Io.tty;
const Fuzz = @This();
const build_runner = @import("root");
gpa: Allocator,
io: Io,
-ttyconf: tty.Config,
mode: Mode,
/// Allocated into `gpa`.
@@ -77,7 +75,6 @@ const CoverageMap = struct {
pub fn init(
gpa: Allocator,
io: Io,
- ttyconf: tty.Config,
all_steps: []const *Build.Step,
root_prog_node: std.Progress.Node,
mode: Mode,
@@ -95,7 +92,7 @@ pub fn init(
if (run.producer == null) continue;
if (run.fuzz_tests.items.len == 0) continue;
try steps.append(gpa, run);
- rebuild_group.async(io, rebuildTestsWorkerRun, .{ run, gpa, ttyconf, rebuild_node });
+ rebuild_group.async(io, rebuildTestsWorkerRun, .{ run, gpa, rebuild_node });
}
if (steps.items.len == 0) fatal("no fuzz tests found", .{});
@@ -115,7 +112,6 @@ pub fn init(
return .{
.gpa = gpa,
.io = io,
- .ttyconf = ttyconf,
.mode = mode,
.run_steps = run_steps,
.group = .init,
@@ -154,14 +150,16 @@ pub fn deinit(fuzz: *Fuzz) void {
fuzz.gpa.free(fuzz.run_steps);
}
-fn rebuildTestsWorkerRun(run: *Step.Run, gpa: Allocator, ttyconf: tty.Config, parent_prog_node: std.Progress.Node) void {
- rebuildTestsWorkerRunFallible(run, gpa, ttyconf, parent_prog_node) catch |err| {
+fn rebuildTestsWorkerRun(run: *Step.Run, gpa: Allocator, parent_prog_node: std.Progress.Node) void {
+ rebuildTestsWorkerRunFallible(run, gpa, parent_prog_node) catch |err| {
const compile = run.producer.?;
log.err("step '{s}': failed to rebuild in fuzz mode: {t}", .{ compile.step.name, err });
};
}
-fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, ttyconf: tty.Config, parent_prog_node: std.Progress.Node) !void {
+fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, parent_prog_node: std.Progress.Node) !void {
+ const graph = run.step.owner.graph;
+ const io = graph.io;
const compile = run.producer.?;
const prog_node = parent_prog_node.start(compile.step.name, 0);
defer prog_node.end();
@@ -174,9 +172,9 @@ fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, ttyconf: tty.Co
if (show_error_msgs or show_compile_errors or show_stderr) {
var buf: [256]u8 = undefined;
- const w, _ = std.debug.lockStderrWriter(&buf);
- defer std.debug.unlockStderrWriter();
- build_runner.printErrorMessages(gpa, &compile.step, .{}, w, ttyconf, .verbose, .indent) catch {};
+ const stderr = try io.lockStderr(&buf, graph.stderr_mode);
+ defer io.unlockStderr();
+ build_runner.printErrorMessages(gpa, &compile.step, .{}, stderr.terminal(), .verbose, .indent) catch {};
}
const rebuilt_bin_path = result catch |err| switch (err) {
@@ -186,12 +184,11 @@ fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, ttyconf: tty.Co
run.rebuilt_executable = try rebuilt_bin_path.join(gpa, compile.out_filename);
}
-fn fuzzWorkerRun(
- fuzz: *Fuzz,
- run: *Step.Run,
- unit_test_index: u32,
-) void {
- const gpa = run.step.owner.allocator;
+fn fuzzWorkerRun(fuzz: *Fuzz, run: *Step.Run, unit_test_index: u32) void {
+ const owner = run.step.owner;
+ const gpa = owner.allocator;
+ const graph = owner.graph;
+ const io = graph.io;
const test_name = run.cached_test_metadata.?.testName(unit_test_index);
const prog_node = fuzz.prog_node.start(test_name, 0);
@@ -200,9 +197,11 @@ fn fuzzWorkerRun(
run.rerunInFuzzMode(fuzz, unit_test_index, prog_node) catch |err| switch (err) {
error.MakeFailed => {
var buf: [256]u8 = undefined;
- const w, _ = std.debug.lockStderrWriter(&buf);
- defer std.debug.unlockStderrWriter();
- build_runner.printErrorMessages(gpa, &run.step, .{}, w, fuzz.ttyconf, .verbose, .indent) catch {};
+ const stderr = io.lockStderr(&buf, graph.stderr_mode) catch |e| switch (e) {
+ error.Canceled => return,
+ };
+ defer io.unlockStderr();
+ build_runner.printErrorMessages(gpa, &run.step, .{}, stderr.terminal(), .verbose, .indent) catch {};
return;
},
else => {
@@ -360,12 +359,13 @@ fn coverageRunCancelable(fuzz: *Fuzz) Io.Cancelable!void {
fn prepareTables(fuzz: *Fuzz, run_step: *Step.Run, coverage_id: u64) error{ OutOfMemory, AlreadyReported, Canceled }!void {
assert(fuzz.mode == .forever);
const ws = fuzz.mode.forever.ws;
+ const gpa = fuzz.gpa;
const io = fuzz.io;
try fuzz.coverage_mutex.lock(io);
defer fuzz.coverage_mutex.unlock(io);
- const gop = try fuzz.coverage_files.getOrPut(fuzz.gpa, coverage_id);
+ const gop = try fuzz.coverage_files.getOrPut(gpa, coverage_id);
if (gop.found_existing) {
// We are fuzzing the same executable with multiple threads.
// Perhaps the same unit test; perhaps a different one. In any
@@ -383,12 +383,13 @@ fn prepareTables(fuzz: *Fuzz, run_step: *Step.Run, coverage_id: u64) error{ OutO
.entry_points = .{},
.start_timestamp = ws.now(),
};
- errdefer gop.value_ptr.coverage.deinit(fuzz.gpa);
+ errdefer gop.value_ptr.coverage.deinit(gpa);
const rebuilt_exe_path = run_step.rebuilt_executable.?;
const target = run_step.producer.?.rootModuleTarget();
var debug_info = std.debug.Info.load(
- fuzz.gpa,
+ gpa,
+ io,
rebuilt_exe_path,
&gop.value_ptr.coverage,
target.ofmt,
@@ -399,21 +400,21 @@ fn prepareTables(fuzz: *Fuzz, run_step: *Step.Run, coverage_id: u64) error{ OutO
});
return error.AlreadyReported;
};
- defer debug_info.deinit(fuzz.gpa);
+ defer debug_info.deinit(gpa);
const coverage_file_path: Build.Cache.Path = .{
.root_dir = run_step.step.owner.cache_root,
.sub_path = "v/" ++ std.fmt.hex(coverage_id),
};
- var coverage_file = coverage_file_path.root_dir.handle.openFile(coverage_file_path.sub_path, .{}) catch |err| {
+ var coverage_file = coverage_file_path.root_dir.handle.openFile(io, coverage_file_path.sub_path, .{}) catch |err| {
log.err("step '{s}': failed to load coverage file '{f}': {t}", .{
run_step.step.name, coverage_file_path, err,
});
return error.AlreadyReported;
};
- defer coverage_file.close();
+ defer coverage_file.close(io);
- const file_size = coverage_file.getEndPos() catch |err| {
+ const file_size = coverage_file.length(io) catch |err| {
log.err("unable to check len of coverage file '{f}': {t}", .{ coverage_file_path, err });
return error.AlreadyReported;
};
@@ -433,14 +434,14 @@ fn prepareTables(fuzz: *Fuzz, run_step: *Step.Run, coverage_id: u64) error{ OutO
const header: *const abi.SeenPcsHeader = @ptrCast(mapped_memory[0..@sizeOf(abi.SeenPcsHeader)]);
const pcs = header.pcAddrs();
- const source_locations = try fuzz.gpa.alloc(Coverage.SourceLocation, pcs.len);
- errdefer fuzz.gpa.free(source_locations);
+ const source_locations = try gpa.alloc(Coverage.SourceLocation, pcs.len);
+ errdefer gpa.free(source_locations);
// Unfortunately the PCs array that LLVM gives us from the 8-bit PC
// counters feature is not sorted.
var sorted_pcs: std.MultiArrayList(struct { pc: u64, index: u32, sl: Coverage.SourceLocation }) = .{};
- defer sorted_pcs.deinit(fuzz.gpa);
- try sorted_pcs.resize(fuzz.gpa, pcs.len);
+ defer sorted_pcs.deinit(gpa);
+ try sorted_pcs.resize(gpa, pcs.len);
@memcpy(sorted_pcs.items(.pc), pcs);
for (sorted_pcs.items(.index), 0..) |*v, i| v.* = @intCast(i);
sorted_pcs.sortUnstable(struct {
@@ -451,7 +452,7 @@ fn prepareTables(fuzz: *Fuzz, run_step: *Step.Run, coverage_id: u64) error{ OutO
}
}{ .addrs = sorted_pcs.items(.pc) });
- debug_info.resolveAddresses(fuzz.gpa, sorted_pcs.items(.pc), sorted_pcs.items(.sl)) catch |err| {
+ debug_info.resolveAddresses(gpa, io, sorted_pcs.items(.pc), sorted_pcs.items(.sl)) catch |err| {
log.err("failed to resolve addresses to source locations: {t}", .{err});
return error.AlreadyReported;
};
@@ -528,12 +529,12 @@ pub fn waitAndPrintReport(fuzz: *Fuzz) void {
.root_dir = cov.run.step.owner.cache_root,
.sub_path = "v/" ++ std.fmt.hex(cov.id),
};
- var coverage_file = coverage_file_path.root_dir.handle.openFile(coverage_file_path.sub_path, .{}) catch |err| {
+ var coverage_file = coverage_file_path.root_dir.handle.openFile(io, coverage_file_path.sub_path, .{}) catch |err| {
fatal("step '{s}': failed to load coverage file '{f}': {t}", .{
cov.run.step.name, coverage_file_path, err,
});
};
- defer coverage_file.close();
+ defer coverage_file.close(io);
const fuzz_abi = std.Build.abi.fuzz;
var rbuf: [0x1000]u8 = undefined;
diff --git a/lib/std/Build/Step.zig b/lib/std/Build/Step.zig
index c247e69461..243dee8604 100644
--- a/lib/std/Build/Step.zig
+++ b/lib/std/Build/Step.zig
@@ -117,7 +117,6 @@ pub const MakeOptions = struct {
// it currently breaks because `std.net.Address` doesn't work there. Work around for now.
.wasm32 => void,
},
- ttyconf: std.Io.tty.Config,
/// If set, this is a timeout to enforce on all individual unit tests, in nanoseconds.
unit_test_timeout_ns: ?u64,
/// Not to be confused with `Build.allocator`, which is an alias of `Build.graph.arena`.
@@ -329,16 +328,17 @@ pub fn cast(step: *Step, comptime T: type) ?*T {
}
/// For debugging purposes, prints identifying information about this Step.
-pub fn dump(step: *Step, w: *Io.Writer, tty_config: Io.tty.Config) void {
+pub fn dump(step: *Step, t: Io.Terminal) void {
+ const w = t.writer;
if (step.debug_stack_trace.instruction_addresses.len > 0) {
w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {};
- std.debug.writeStackTrace(&step.debug_stack_trace, w, tty_config) catch {};
+ std.debug.writeStackTrace(&step.debug_stack_trace, t) catch {};
} else {
const field = "debug_stack_frames_count";
comptime assert(@hasField(Build, field));
- tty_config.setColor(w, .yellow) catch {};
+ t.setColor(.yellow) catch {};
w.print("name: '{s}'. no stack trace collected for this step, see std.Build." ++ field ++ "\n", .{step.name}) catch {};
- tty_config.setColor(w, .reset) catch {};
+ t.setColor(.reset) catch {};
}
}
@@ -350,6 +350,7 @@ pub fn captureChildProcess(
argv: []const []const u8,
) !std.process.Child.RunResult {
const arena = s.owner.allocator;
+ const io = s.owner.graph.io;
// If an error occurs, it's happened in this command:
assert(s.result_failed_command == null);
@@ -358,8 +359,7 @@ pub fn captureChildProcess(
try handleChildProcUnsupported(s);
try handleVerbose(s.owner, null, argv);
- const result = std.process.Child.run(.{
- .allocator = arena,
+ const result = std.process.Child.run(arena, io, .{
.argv = argv,
.progress_node = progress_node,
}) catch |err| return s.fail("failed to run {s}: {t}", .{ argv[0], err });
@@ -401,6 +401,9 @@ pub fn evalZigProcess(
web_server: ?*Build.WebServer,
gpa: Allocator,
) !?Path {
+ const b = s.owner;
+ const io = b.graph.io;
+
// If an error occurs, it's happened in this command:
assert(s.result_failed_command == null);
s.result_failed_command = try allocPrintCmd(gpa, null, argv);
@@ -411,7 +414,7 @@ pub fn evalZigProcess(
const result = zigProcessUpdate(s, zp, watch, web_server, gpa) catch |err| switch (err) {
error.BrokenPipe => {
// Process restart required.
- const term = zp.child.wait() catch |e| {
+ const term = zp.child.wait(io) catch |e| {
return s.fail("unable to wait for {s}: {t}", .{ argv[0], e });
};
_ = term;
@@ -427,7 +430,7 @@ pub fn evalZigProcess(
if (s.result_error_msgs.items.len > 0 and result == null) {
// Crash detected.
- const term = zp.child.wait() catch |e| {
+ const term = zp.child.wait(io) catch |e| {
return s.fail("unable to wait for {s}: {t}", .{ argv[0], e });
};
s.result_peak_rss = zp.child.resource_usage_statistics.getMaxRss() orelse 0;
@@ -439,7 +442,6 @@ pub fn evalZigProcess(
return result;
}
assert(argv.len != 0);
- const b = s.owner;
const arena = b.allocator;
try handleChildProcUnsupported(s);
@@ -453,7 +455,7 @@ pub fn evalZigProcess(
child.request_resource_usage_statistics = true;
child.progress_node = prog_node;
- child.spawn() catch |err| return s.fail("failed to spawn zig compiler {s}: {t}", .{ argv[0], err });
+ child.spawn(io) catch |err| return s.fail("failed to spawn zig compiler {s}: {t}", .{ argv[0], err });
const zp = try gpa.create(ZigProcess);
zp.* = .{
@@ -474,10 +476,10 @@ pub fn evalZigProcess(
if (!watch) {
// Send EOF to stdin.
- zp.child.stdin.?.close();
+ zp.child.stdin.?.close(io);
zp.child.stdin = null;
- const term = zp.child.wait() catch |err| {
+ const term = zp.child.wait(io) catch |err| {
return s.fail("unable to wait for {s}: {t}", .{ argv[0], err });
};
s.result_peak_rss = zp.child.resource_usage_statistics.getMaxRss() orelse 0;
@@ -504,36 +506,34 @@ pub fn evalZigProcess(
return result;
}
-/// Wrapper around `std.fs.Dir.updateFile` that handles verbose and error output.
+/// Wrapper around `Io.Dir.updateFile` that handles verbose and error output.
pub fn installFile(s: *Step, src_lazy_path: Build.LazyPath, dest_path: []const u8) !Io.Dir.PrevStatus {
const b = s.owner;
const io = b.graph.io;
const src_path = src_lazy_path.getPath3(b, s);
try handleVerbose(b, null, &.{ "install", "-C", b.fmt("{f}", .{src_path}), dest_path });
- return Io.Dir.updateFile(src_path.root_dir.handle.adaptToNewApi(), io, src_path.sub_path, .cwd(), dest_path, .{}) catch |err| {
- return s.fail("unable to update file from '{f}' to '{s}': {t}", .{
- src_path, dest_path, err,
- });
- };
+ return Io.Dir.updateFile(src_path.root_dir.handle, io, src_path.sub_path, .cwd(), dest_path, .{}) catch |err|
+ return s.fail("unable to update file from '{f}' to '{s}': {t}", .{ src_path, dest_path, err });
}
-/// Wrapper around `std.fs.Dir.makePathStatus` that handles verbose and error output.
-pub fn installDir(s: *Step, dest_path: []const u8) !std.fs.Dir.MakePathStatus {
+/// Wrapper around `Io.Dir.createDirPathStatus` that handles verbose and error output.
+pub fn installDir(s: *Step, dest_path: []const u8) !Io.Dir.CreatePathStatus {
const b = s.owner;
+ const io = b.graph.io;
try handleVerbose(b, null, &.{ "install", "-d", dest_path });
- return std.fs.cwd().makePathStatus(dest_path) catch |err| {
+ return Io.Dir.cwd().createDirPathStatus(io, dest_path, .default_dir) catch |err|
return s.fail("unable to create dir '{s}': {t}", .{ dest_path, err });
- };
}
fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool, web_server: ?*Build.WebServer, gpa: Allocator) !?Path {
const b = s.owner;
const arena = b.allocator;
+ const io = b.graph.io;
var timer = try std.time.Timer.start();
- try sendMessage(zp.child.stdin.?, .update);
- if (!watch) try sendMessage(zp.child.stdin.?, .exit);
+ try sendMessage(io, zp.child.stdin.?, .update);
+ if (!watch) try sendMessage(io, zp.child.stdin.?, .exit);
var result: ?Path = null;
@@ -670,12 +670,12 @@ fn clearZigProcess(s: *Step, gpa: Allocator) void {
}
}
-fn sendMessage(file: std.fs.File, tag: std.zig.Client.Message.Tag) !void {
+fn sendMessage(io: Io, file: Io.File, tag: std.zig.Client.Message.Tag) !void {
const header: std.zig.Client.Message.Header = .{
.tag = tag,
.bytes_len = 0,
};
- var w = file.writer(&.{});
+ var w = file.writer(io, &.{});
w.interface.writeStruct(header, .little) catch |err| switch (err) {
error.WriteFailed => return w.err.?,
};
@@ -898,7 +898,7 @@ pub fn addWatchInput(step: *Step, lazy_file: Build.LazyPath) Allocator.Error!voi
try addWatchInputFromPath(step, .{
.root_dir = .{
.path = null,
- .handle = std.fs.cwd(),
+ .handle = Io.Dir.cwd(),
},
.sub_path = std.fs.path.dirname(path_string) orelse "",
}, std.fs.path.basename(path_string));
@@ -923,7 +923,7 @@ pub fn addDirectoryWatchInput(step: *Step, lazy_directory: Build.LazyPath) Alloc
try addDirectoryWatchInputFromPath(step, .{
.root_dir = .{
.path = null,
- .handle = std.fs.cwd(),
+ .handle = Io.Dir.cwd(),
},
.sub_path = path_string,
});
diff --git a/lib/std/Build/Step/CheckFile.zig b/lib/std/Build/Step/CheckFile.zig
index efeedc8b80..1c3813ca82 100644
--- a/lib/std/Build/Step/CheckFile.zig
+++ b/lib/std/Build/Step/CheckFile.zig
@@ -3,7 +3,9 @@
//! TODO: generalize the code in std.testing.expectEqualStrings and make this
//! CheckFile step produce those helpful diagnostics when there is not a match.
const CheckFile = @This();
+
const std = @import("std");
+const Io = std.Io;
const Step = std.Build.Step;
const fs = std.fs;
const mem = std.mem;
@@ -49,11 +51,12 @@ pub fn setName(check_file: *CheckFile, name: []const u8) void {
fn make(step: *Step, options: Step.MakeOptions) !void {
_ = options;
const b = step.owner;
+ const io = b.graph.io;
const check_file: *CheckFile = @fieldParentPtr("step", step);
try step.singleUnchangingWatchInput(check_file.source);
const src_path = check_file.source.getPath2(b, step);
- const contents = fs.cwd().readFileAlloc(src_path, b.allocator, .limited(check_file.max_bytes)) catch |err| {
+ const contents = Io.Dir.cwd().readFileAlloc(io, src_path, b.allocator, .limited(check_file.max_bytes)) catch |err| {
return step.fail("unable to read '{s}': {s}", .{
src_path, @errorName(err),
});
diff --git a/lib/std/Build/Step/CheckObject.zig b/lib/std/Build/Step/CheckObject.zig
index c6c11ce2b9..ac8fafaa3f 100644
--- a/lib/std/Build/Step/CheckObject.zig
+++ b/lib/std/Build/Step/CheckObject.zig
@@ -547,12 +547,14 @@ pub fn checkComputeCompare(
fn make(step: *Step, make_options: Step.MakeOptions) !void {
_ = make_options;
const b = step.owner;
+ const io = b.graph.io;
const gpa = b.allocator;
const check_object: *CheckObject = @fieldParentPtr("step", step);
try step.singleUnchangingWatchInput(check_object.source);
const src_path = check_object.source.getPath3(b, step);
const contents = src_path.root_dir.handle.readFileAllocOptions(
+ io,
src_path.sub_path,
gpa,
.limited(check_object.max_bytes),
diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig
index c57c7750be..0454e5b79d 100644
--- a/lib/std/Build/Step/Compile.zig
+++ b/lib/std/Build/Step/Compile.zig
@@ -1,12 +1,15 @@
+const Compile = @This();
const builtin = @import("builtin");
+
const std = @import("std");
+const Io = std.Io;
const mem = std.mem;
const fs = std.fs;
const assert = std.debug.assert;
const panic = std.debug.panic;
const StringHashMap = std.StringHashMap;
const Sha256 = std.crypto.hash.sha2.Sha256;
-const Allocator = mem.Allocator;
+const Allocator = std.mem.Allocator;
const Step = std.Build.Step;
const LazyPath = std.Build.LazyPath;
const PkgConfigPkg = std.Build.PkgConfigPkg;
@@ -15,7 +18,6 @@ const RunError = std.Build.RunError;
const Module = std.Build.Module;
const InstallDir = std.Build.InstallDir;
const GeneratedFile = std.Build.GeneratedFile;
-const Compile = @This();
const Path = std.Build.Cache.Path;
pub const base_id: Step.Id = .compile;
@@ -920,20 +922,24 @@ const CliNamedModules = struct {
}
};
-fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking_step: ?*Step) []const u8 {
+fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking_step: ?*Step) ![]const u8 {
+ const step = &compile.step;
+ const b = step.owner;
+ const graph = b.graph;
+ const io = graph.io;
const maybe_path: ?*GeneratedFile = @field(compile, tag_name);
const generated_file = maybe_path orelse {
- const w, const ttyconf = std.debug.lockStderrWriter(&.{});
- std.Build.dumpBadGetPathHelp(&compile.step, w, ttyconf, compile.step.owner, asking_step) catch {};
- std.debug.unlockStderrWriter();
+ const stderr = try io.lockStderr(&.{}, graph.stderr_mode);
+ std.Build.dumpBadGetPathHelp(&compile.step, stderr.terminal(), compile.step.owner, asking_step) catch {};
+ io.unlockStderr();
@panic("missing emit option for " ++ tag_name);
};
const path = generated_file.path orelse {
- const w, const ttyconf = std.debug.lockStderrWriter(&.{});
- std.Build.dumpBadGetPathHelp(&compile.step, w, ttyconf, compile.step.owner, asking_step) catch {};
- std.debug.unlockStderrWriter();
+ const stderr = try io.lockStderr(&.{}, graph.stderr_mode);
+ std.Build.dumpBadGetPathHelp(&compile.step, stderr.terminal(), compile.step.owner, asking_step) catch {};
+ io.unlockStderr();
@panic(tag_name ++ " is null. Is there a missing step dependency?");
};
@@ -1147,9 +1153,9 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
// For everything else, we directly link
// against the library file.
const full_path_lib = if (other_produces_implib)
- other.getGeneratedFilePath("generated_implib", &compile.step)
+ try other.getGeneratedFilePath("generated_implib", &compile.step)
else
- other.getGeneratedFilePath("generated_bin", &compile.step);
+ try other.getGeneratedFilePath("generated_bin", &compile.step);
try zig_args.append(full_path_lib);
total_linker_objects += 1;
@@ -1561,19 +1567,22 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
}
// -I and -L arguments that appear after the last --mod argument apply to all modules.
+ const cwd: Io.Dir = .cwd();
+ const io = b.graph.io;
+
for (b.search_prefixes.items) |search_prefix| {
- var prefix_dir = fs.cwd().openDir(search_prefix, .{}) catch |err| {
+ var prefix_dir = cwd.openDir(io, search_prefix, .{}) catch |err| {
return step.fail("unable to open prefix directory '{s}': {s}", .{
search_prefix, @errorName(err),
});
};
- defer prefix_dir.close();
+ defer prefix_dir.close(io);
// Avoid passing -L and -I flags for nonexistent directories.
// This prevents a warning, that should probably be upgraded to an error in Zig's
// CLI parsing code, when the linker sees an -L directory that does not exist.
- if (prefix_dir.access("lib", .{})) |_| {
+ if (prefix_dir.access(io, "lib", .{})) |_| {
try zig_args.appendSlice(&.{
"-L", b.pathJoin(&.{ search_prefix, "lib" }),
});
@@ -1584,7 +1593,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
}),
}
- if (prefix_dir.access("include", .{})) |_| {
+ if (prefix_dir.access(io, "include", .{})) |_| {
try zig_args.appendSlice(&.{
"-I", b.pathJoin(&.{ search_prefix, "include" }),
});
@@ -1660,7 +1669,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
args_length += arg.len + 1; // +1 to account for null terminator
}
if (args_length >= 30 * 1024) {
- try b.cache_root.handle.makePath("args");
+ try b.cache_root.handle.createDirPath(io, "args");
const args_to_escape = zig_args.items[2..];
var escaped_args = try std.array_list.Managed([]const u8).initCapacity(arena, args_to_escape.len);
@@ -1693,18 +1702,18 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
_ = try std.fmt.bufPrint(&args_hex_hash, "{x}", .{&args_hash});
const args_file = "args" ++ fs.path.sep_str ++ args_hex_hash;
- if (b.cache_root.handle.access(args_file, .{})) |_| {
+ if (b.cache_root.handle.access(io, args_file, .{})) |_| {
// The args file is already present from a previous run.
} else |err| switch (err) {
error.FileNotFound => {
- try b.cache_root.handle.makePath("tmp");
+ try b.cache_root.handle.createDirPath(io, "tmp");
const rand_int = std.crypto.random.int(u64);
const tmp_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);
- try b.cache_root.handle.writeFile(.{ .sub_path = tmp_path, .data = args });
- defer b.cache_root.handle.deleteFile(tmp_path) catch {
+ try b.cache_root.handle.writeFile(io, .{ .sub_path = tmp_path, .data = args });
+ defer b.cache_root.handle.deleteFile(io, tmp_path) catch {
// It's fine if the temporary file can't be cleaned up.
};
- b.cache_root.handle.rename(tmp_path, args_file) catch |rename_err| switch (rename_err) {
+ b.cache_root.handle.rename(tmp_path, b.cache_root.handle, args_file, io) catch |rename_err| switch (rename_err) {
error.PathAlreadyExists => {
// The args file was created by another concurrent build process.
},
@@ -1816,18 +1825,20 @@ pub fn doAtomicSymLinks(
filename_name_only: []const u8,
) !void {
const b = step.owner;
+ const io = b.graph.io;
const out_dir = fs.path.dirname(output_path) orelse ".";
const out_basename = fs.path.basename(output_path);
// sym link for libfoo.so.1 to libfoo.so.1.2.3
const major_only_path = b.pathJoin(&.{ out_dir, filename_major_only });
- fs.cwd().atomicSymLink(out_basename, major_only_path, .{}) catch |err| {
+ const cwd: Io.Dir = .cwd();
+ cwd.symLinkAtomic(io, out_basename, major_only_path, .{}) catch |err| {
return step.fail("unable to symlink {s} -> {s}: {s}", .{
major_only_path, out_basename, @errorName(err),
});
};
// sym link for libfoo.so to libfoo.so.1
const name_only_path = b.pathJoin(&.{ out_dir, filename_name_only });
- fs.cwd().atomicSymLink(filename_major_only, name_only_path, .{}) catch |err| {
+ cwd.symLinkAtomic(io, filename_major_only, name_only_path, .{}) catch |err| {
return step.fail("Unable to symlink {s} -> {s}: {s}", .{
name_only_path, filename_major_only, @errorName(err),
});
@@ -1897,7 +1908,7 @@ fn checkCompileErrors(compile: *Compile) !void {
try actual_eb.renderToWriter(.{
.include_reference_trace = false,
.include_source_line = false,
- }, &aw.writer, .no_color);
+ }, &aw.writer);
break :ae try aw.toOwnedSlice();
};
diff --git a/lib/std/Build/Step/ConfigHeader.zig b/lib/std/Build/Step/ConfigHeader.zig
index df2419764d..b55efc0da4 100644
--- a/lib/std/Build/Step/ConfigHeader.zig
+++ b/lib/std/Build/Step/ConfigHeader.zig
@@ -1,5 +1,7 @@
-const std = @import("std");
const ConfigHeader = @This();
+
+const std = @import("std");
+const Io = std.Io;
const Step = std.Build.Step;
const Allocator = std.mem.Allocator;
const Writer = std.Io.Writer;
@@ -182,6 +184,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
const gpa = b.allocator;
const arena = b.allocator;
+ const io = b.graph.io;
var man = b.graph.cache.obtain();
defer man.deinit();
@@ -205,7 +208,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
.autoconf_undef, .autoconf_at => |file_source| {
try bw.writeAll(c_generated_line);
const src_path = file_source.getPath2(b, step);
- const contents = std.fs.cwd().readFileAlloc(src_path, arena, .limited(config_header.max_bytes)) catch |err| {
+ const contents = Io.Dir.cwd().readFileAlloc(io, src_path, arena, .limited(config_header.max_bytes)) catch |err| {
return step.fail("unable to read autoconf input file '{s}': {s}", .{
src_path, @errorName(err),
});
@@ -219,7 +222,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
.cmake => |file_source| {
try bw.writeAll(c_generated_line);
const src_path = file_source.getPath2(b, step);
- const contents = std.fs.cwd().readFileAlloc(src_path, arena, .limited(config_header.max_bytes)) catch |err| {
+ const contents = Io.Dir.cwd().readFileAlloc(io, src_path, arena, .limited(config_header.max_bytes)) catch |err| {
return step.fail("unable to read cmake input file '{s}': {s}", .{
src_path, @errorName(err),
});
@@ -255,13 +258,13 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
const sub_path = b.pathJoin(&.{ "o", &digest, config_header.include_path });
const sub_path_dirname = std.fs.path.dirname(sub_path).?;
- b.cache_root.handle.makePath(sub_path_dirname) catch |err| {
+ b.cache_root.handle.createDirPath(io, sub_path_dirname) catch |err| {
return step.fail("unable to make path '{f}{s}': {s}", .{
b.cache_root, sub_path_dirname, @errorName(err),
});
};
- b.cache_root.handle.writeFile(.{ .sub_path = sub_path, .data = output }) catch |err| {
+ b.cache_root.handle.writeFile(io, .{ .sub_path = sub_path, .data = output }) catch |err| {
return step.fail("unable to write file '{f}{s}': {s}", .{
b.cache_root, sub_path, @errorName(err),
});
diff --git a/lib/std/Build/Step/InstallArtifact.zig b/lib/std/Build/Step/InstallArtifact.zig
index c203ae924b..019d465f01 100644
--- a/lib/std/Build/Step/InstallArtifact.zig
+++ b/lib/std/Build/Step/InstallArtifact.zig
@@ -119,6 +119,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
_ = options;
const install_artifact: *InstallArtifact = @fieldParentPtr("step", step);
const b = step.owner;
+ const io = b.graph.io;
var all_cached = true;
@@ -163,15 +164,15 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
const src_dir_path = dir.source.getPath3(b, step);
const full_h_prefix = b.getInstallPath(h_dir, dir.dest_rel_path);
- var src_dir = src_dir_path.root_dir.handle.openDir(src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| {
+ var src_dir = src_dir_path.root_dir.handle.openDir(io, src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| {
return step.fail("unable to open source directory '{f}': {s}", .{
src_dir_path, @errorName(err),
});
};
- defer src_dir.close();
+ defer src_dir.close(io);
var it = try src_dir.walk(b.allocator);
- next_entry: while (try it.next()) |entry| {
+ next_entry: while (try it.next(io)) |entry| {
for (dir.options.exclude_extensions) |ext| {
if (std.mem.endsWith(u8, entry.path, ext)) continue :next_entry;
}
diff --git a/lib/std/Build/Step/InstallDir.zig b/lib/std/Build/Step/InstallDir.zig
index fd8a7d113f..d03e72ca75 100644
--- a/lib/std/Build/Step/InstallDir.zig
+++ b/lib/std/Build/Step/InstallDir.zig
@@ -58,21 +58,20 @@ pub fn create(owner: *std.Build, options: Options) *InstallDir {
fn make(step: *Step, options: Step.MakeOptions) !void {
_ = options;
const b = step.owner;
+ const io = b.graph.io;
const install_dir: *InstallDir = @fieldParentPtr("step", step);
step.clearWatchInputs();
const arena = b.allocator;
const dest_prefix = b.getInstallPath(install_dir.options.install_dir, install_dir.options.install_subdir);
const src_dir_path = install_dir.options.source_dir.getPath3(b, step);
const need_derived_inputs = try step.addDirectoryWatchInput(install_dir.options.source_dir);
- var src_dir = src_dir_path.root_dir.handle.openDir(src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| {
- return step.fail("unable to open source directory '{f}': {s}", .{
- src_dir_path, @errorName(err),
- });
+ var src_dir = src_dir_path.root_dir.handle.openDir(io, src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| {
+ return step.fail("unable to open source directory '{f}': {t}", .{ src_dir_path, err });
};
- defer src_dir.close();
+ defer src_dir.close(io);
var it = try src_dir.walk(arena);
var all_cached = true;
- next_entry: while (try it.next()) |entry| {
+ next_entry: while (try it.next(io)) |entry| {
for (install_dir.options.exclude_extensions) |ext| {
if (mem.endsWith(u8, entry.path, ext)) continue :next_entry;
}
diff --git a/lib/std/Build/Step/ObjCopy.zig b/lib/std/Build/Step/ObjCopy.zig
index b5f058ddfc..ea0714adf9 100644
--- a/lib/std/Build/Step/ObjCopy.zig
+++ b/lib/std/Build/Step/ObjCopy.zig
@@ -3,7 +3,7 @@ const ObjCopy = @This();
const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator;
-const File = std.fs.File;
+const File = std.Io.File;
const InstallDir = std.Build.InstallDir;
const Step = std.Build.Step;
const elf = std.elf;
@@ -143,6 +143,7 @@ pub fn getOutputSeparatedDebug(objcopy: *const ObjCopy) ?std.Build.LazyPath {
fn make(step: *Step, options: Step.MakeOptions) !void {
const prog_node = options.progress_node;
const b = step.owner;
+ const io = b.graph.io;
const objcopy: *ObjCopy = @fieldParentPtr("step", step);
try step.singleUnchangingWatchInput(objcopy.input_file);
@@ -176,7 +177,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
const cache_path = "o" ++ fs.path.sep_str ++ digest;
const full_dest_path = try b.cache_root.join(b.allocator, &.{ cache_path, objcopy.basename });
const full_dest_path_debug = try b.cache_root.join(b.allocator, &.{ cache_path, b.fmt("{s}.debug", .{objcopy.basename}) });
- b.cache_root.handle.makePath(cache_path) catch |err| {
+ b.cache_root.handle.createDirPath(io, cache_path) catch |err| {
return step.fail("unable to make path {s}: {s}", .{ cache_path, @errorName(err) });
};
diff --git a/lib/std/Build/Step/Options.zig b/lib/std/Build/Step/Options.zig
index 441928d5b8..610d417aea 100644
--- a/lib/std/Build/Step/Options.zig
+++ b/lib/std/Build/Step/Options.zig
@@ -1,12 +1,13 @@
-const std = @import("std");
+const Options = @This();
const builtin = @import("builtin");
+
+const std = @import("std");
+const Io = std.Io;
const fs = std.fs;
const Step = std.Build.Step;
const GeneratedFile = std.Build.GeneratedFile;
const LazyPath = std.Build.LazyPath;
-const Options = @This();
-
pub const base_id: Step.Id = .options;
step: Step,
@@ -441,6 +442,7 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
_ = make_options;
const b = step.owner;
+ const io = b.graph.io;
const options: *Options = @fieldParentPtr("step", step);
for (options.args.items) |item| {
@@ -468,18 +470,15 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
// Optimize for the hot path. Stat the file, and if it already exists,
// cache hit.
- if (b.cache_root.handle.access(sub_path, .{})) |_| {
+ if (b.cache_root.handle.access(io, sub_path, .{})) |_| {
// This is the hot path, success.
step.result_cached = true;
return;
} else |outer_err| switch (outer_err) {
error.FileNotFound => {
const sub_dirname = fs.path.dirname(sub_path).?;
- b.cache_root.handle.makePath(sub_dirname) catch |e| {
- return step.fail("unable to make path '{f}{s}': {s}", .{
- b.cache_root, sub_dirname, @errorName(e),
- });
- };
+ b.cache_root.handle.createDirPath(io, sub_dirname) catch |e|
+ return step.fail("unable to make path '{f}{s}': {t}", .{ b.cache_root, sub_dirname, e });
const rand_int = std.crypto.random.int(u64);
const tmp_sub_path = "tmp" ++ fs.path.sep_str ++
@@ -487,40 +486,40 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
basename;
const tmp_sub_path_dirname = fs.path.dirname(tmp_sub_path).?;
- b.cache_root.handle.makePath(tmp_sub_path_dirname) catch |err| {
- return step.fail("unable to make temporary directory '{f}{s}': {s}", .{
- b.cache_root, tmp_sub_path_dirname, @errorName(err),
+ b.cache_root.handle.createDirPath(io, tmp_sub_path_dirname) catch |err| {
+ return step.fail("unable to make temporary directory '{f}{s}': {t}", .{
+ b.cache_root, tmp_sub_path_dirname, err,
});
};
- b.cache_root.handle.writeFile(.{ .sub_path = tmp_sub_path, .data = options.contents.items }) catch |err| {
- return step.fail("unable to write options to '{f}{s}': {s}", .{
- b.cache_root, tmp_sub_path, @errorName(err),
+ b.cache_root.handle.writeFile(io, .{ .sub_path = tmp_sub_path, .data = options.contents.items }) catch |err| {
+ return step.fail("unable to write options to '{f}{s}': {t}", .{
+ b.cache_root, tmp_sub_path, err,
});
};
- b.cache_root.handle.rename(tmp_sub_path, sub_path) catch |err| switch (err) {
+ b.cache_root.handle.rename(tmp_sub_path, b.cache_root.handle, sub_path, io) catch |err| switch (err) {
error.PathAlreadyExists => {
// Other process beat us to it. Clean up the temp file.
- b.cache_root.handle.deleteFile(tmp_sub_path) catch |e| {
- try step.addError("warning: unable to delete temp file '{f}{s}': {s}", .{
- b.cache_root, tmp_sub_path, @errorName(e),
+ b.cache_root.handle.deleteFile(io, tmp_sub_path) catch |e| {
+ try step.addError("warning: unable to delete temp file '{f}{s}': {t}", .{
+ b.cache_root, tmp_sub_path, e,
});
};
step.result_cached = true;
return;
},
else => {
- return step.fail("unable to rename options from '{f}{s}' to '{f}{s}': {s}", .{
- b.cache_root, tmp_sub_path,
- b.cache_root, sub_path,
- @errorName(err),
+ return step.fail("unable to rename options from '{f}{s}' to '{f}{s}': {t}", .{
+ b.cache_root, tmp_sub_path,
+ b.cache_root, sub_path,
+ err,
});
},
};
},
- else => |e| return step.fail("unable to access options file '{f}{s}': {s}", .{
- b.cache_root, sub_path, @errorName(e),
+ else => |e| return step.fail("unable to access options file '{f}{s}': {t}", .{
+ b.cache_root, sub_path, e,
}),
}
}
@@ -544,11 +543,11 @@ test Options {
.cache = .{
.io = io,
.gpa = arena.allocator(),
- .manifest_dir = std.fs.cwd(),
+ .manifest_dir = Io.Dir.cwd(),
},
.zig_exe = "test",
.env_map = std.process.EnvMap.init(arena.allocator()),
- .global_cache_root = .{ .path = "test", .handle = std.fs.cwd() },
+ .global_cache_root = .{ .path = "test", .handle = Io.Dir.cwd() },
.host = .{
.query = .{},
.result = try std.zig.system.resolveTargetQuery(io, .{}),
@@ -559,8 +558,8 @@ test Options {
var builder = try std.Build.create(
&graph,
- .{ .path = "test", .handle = std.fs.cwd() },
- .{ .path = "test", .handle = std.fs.cwd() },
+ .{ .path = "test", .handle = Io.Dir.cwd() },
+ .{ .path = "test", .handle = Io.Dir.cwd() },
&.{},
);
diff --git a/lib/std/Build/Step/RemoveDir.zig b/lib/std/Build/Step/RemoveDir.zig
index e2d4c02abc..6f933da9ee 100644
--- a/lib/std/Build/Step/RemoveDir.zig
+++ b/lib/std/Build/Step/RemoveDir.zig
@@ -27,6 +27,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
_ = options;
const b = step.owner;
+ const io = b.graph.io;
const remove_dir: *RemoveDir = @fieldParentPtr("step", step);
step.clearWatchInputs();
@@ -34,15 +35,11 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
const full_doomed_path = remove_dir.doomed_path.getPath2(b, step);
- b.build_root.handle.deleteTree(full_doomed_path) catch |err| {
+ b.build_root.handle.deleteTree(io, full_doomed_path) catch |err| {
if (b.build_root.path) |base| {
- return step.fail("unable to recursively delete path '{s}/{s}': {s}", .{
- base, full_doomed_path, @errorName(err),
- });
+ return step.fail("unable to recursively delete path '{s}/{s}': {t}", .{ base, full_doomed_path, err });
} else {
- return step.fail("unable to recursively delete path '{s}': {s}", .{
- full_doomed_path, @errorName(err),
- });
+ return step.fail("unable to recursively delete path '{s}': {t}", .{ full_doomed_path, err });
}
};
}
diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig
index 28c09e1faf..c0ba7f0cee 100644
--- a/lib/std/Build/Step/Run.zig
+++ b/lib/std/Build/Step/Run.zig
@@ -1,15 +1,16 @@
-const std = @import("std");
+const Run = @This();
const builtin = @import("builtin");
+
+const std = @import("std");
+const Io = std.Io;
const Build = std.Build;
-const Step = Build.Step;
-const fs = std.fs;
+const Step = std.Build.Step;
+const Dir = std.Io.Dir;
const mem = std.mem;
const process = std.process;
-const EnvMap = process.EnvMap;
+const EnvMap = std.process.EnvMap;
const assert = std.debug.assert;
-const Path = Build.Cache.Path;
-
-const Run = @This();
+const Path = std.Build.Cache.Path;
pub const base_id: Step.Id = .run;
@@ -25,19 +26,7 @@ cwd: ?Build.LazyPath,
env_map: ?*EnvMap,
/// Controls the `NO_COLOR` and `CLICOLOR_FORCE` environment variables.
-color: enum {
- /// `CLICOLOR_FORCE` is set, and `NO_COLOR` is unset.
- enable,
- /// `NO_COLOR` is set, and `CLICOLOR_FORCE` is unset.
- disable,
- /// If the build runner is using color, equivalent to `.enable`. Otherwise, equivalent to `.disable`.
- inherit,
- /// If stderr is captured or checked, equivalent to `.disable`. Otherwise, equivalent to `.inherit`.
- auto,
- /// The build runner does not modify the `CLICOLOR_FORCE` or `NO_COLOR` environment variables.
- /// They are treated like normal variables, so can be controlled through `setEnvironmentVariable`.
- manual,
-} = .auto,
+color: Color = .auto,
/// When `true` prevents `ZIG_PROGRESS` environment variable from being passed
/// to the child process, which otherwise would be used for the child to send
@@ -111,6 +100,20 @@ rebuilt_executable: ?Path,
/// If this Run step was produced by a Compile step, it is tracked here.
producer: ?*Step.Compile,
+pub const Color = enum {
+ /// `CLICOLOR_FORCE` is set, and `NO_COLOR` is unset.
+ enable,
+ /// `NO_COLOR` is set, and `CLICOLOR_FORCE` is unset.
+ disable,
+ /// If the build runner is using color, equivalent to `.enable`. Otherwise, equivalent to `.disable`.
+ inherit,
+ /// If stderr is captured or checked, equivalent to `.disable`. Otherwise, equivalent to `.inherit`.
+ auto,
+ /// The build runner does not modify the `CLICOLOR_FORCE` or `NO_COLOR` environment variables.
+ /// They are treated like normal variables, so can be controlled through `setEnvironmentVariable`.
+ manual,
+};
+
pub const StdIn = union(enum) {
none,
bytes: []const u8,
@@ -564,7 +567,7 @@ pub fn addPathDir(run: *Run, search_path: []const u8) void {
if (prev_path) |pp| {
const new_path = b.fmt("{s}{c}{s}", .{
pp,
- if (use_wine) fs.path.delimiter_windows else fs.path.delimiter,
+ if (use_wine) Dir.path.delimiter_windows else Dir.path.delimiter,
search_path,
});
env_map.put(key, new_path) catch @panic("OOM");
@@ -747,7 +750,7 @@ fn checksContainStderr(checks: []const StdIo.Check) bool {
fn convertPathArg(run: *Run, path: Build.Cache.Path) []const u8 {
const b = run.step.owner;
const path_str = path.toString(b.graph.arena) catch @panic("OOM");
- if (std.fs.path.isAbsolute(path_str)) {
+ if (Dir.path.isAbsolute(path_str)) {
// Absolute paths don't need changing.
return path_str;
}
@@ -755,19 +758,19 @@ fn convertPathArg(run: *Run, path: Build.Cache.Path) []const u8 {
const child_lazy_cwd = run.cwd orelse break :rel path_str;
const child_cwd = child_lazy_cwd.getPath3(b, &run.step).toString(b.graph.arena) catch @panic("OOM");
// Convert it from relative to *our* cwd, to relative to the *child's* cwd.
- break :rel std.fs.path.relative(b.graph.arena, child_cwd, path_str) catch @panic("OOM");
+ break :rel Dir.path.relative(b.graph.arena, child_cwd, path_str) catch @panic("OOM");
};
// Not every path can be made relative, e.g. if the path and the child cwd are on different
// disk designators on Windows. In that case, `relative` will return an absolute path which we can
// just return.
- if (std.fs.path.isAbsolute(child_cwd_rel)) {
+ if (Dir.path.isAbsolute(child_cwd_rel)) {
return child_cwd_rel;
}
// We're not done yet. In some cases this path must be prefixed with './':
// * On POSIX, the executable name cannot be a single component like 'foo'
// * Some executables might treat a leading '-' like a flag, which we must avoid
// There's no harm in it, so just *always* apply this prefix.
- return std.fs.path.join(b.graph.arena, &.{ ".", child_cwd_rel }) catch @panic("OOM");
+ return Dir.path.join(b.graph.arena, &.{ ".", child_cwd_rel }) catch @panic("OOM");
}
const IndexedOutput = struct {
@@ -845,13 +848,13 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
errdefer result.deinit();
result.writer.writeAll(file_plp.prefix) catch return error.OutOfMemory;
- const file = file_path.root_dir.handle.openFile(file_path.subPathOrDot(), .{}) catch |err| {
+ const file = file_path.root_dir.handle.openFile(io, file_path.subPathOrDot(), .{}) catch |err| {
return step.fail(
"unable to open input file '{f}': {t}",
.{ file_path, err },
);
};
- defer file.close();
+ defer file.close(io);
var buf: [1024]u8 = undefined;
var file_reader = file.reader(io, &buf);
@@ -964,15 +967,15 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
&digest,
);
- const output_dir_path = "o" ++ fs.path.sep_str ++ &digest;
+ const output_dir_path = "o" ++ Dir.path.sep_str ++ &digest;
for (output_placeholders.items) |placeholder| {
const output_sub_path = b.pathJoin(&.{ output_dir_path, placeholder.output.basename });
const output_sub_dir_path = switch (placeholder.tag) {
- .output_file => fs.path.dirname(output_sub_path).?,
+ .output_file => Dir.path.dirname(output_sub_path).?,
.output_directory => output_sub_path,
else => unreachable,
};
- b.cache_root.handle.makePath(output_sub_dir_path) catch |err| {
+ b.cache_root.handle.createDirPath(io, output_sub_dir_path) catch |err| {
return step.fail("unable to make path '{f}{s}': {s}", .{
b.cache_root, output_sub_dir_path, @errorName(err),
});
@@ -994,17 +997,17 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
// We do not know the final output paths yet, use temp paths to run the command.
const rand_int = std.crypto.random.int(u64);
- const tmp_dir_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);
+ const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int);
for (output_placeholders.items) |placeholder| {
const output_components = .{ tmp_dir_path, placeholder.output.basename };
const output_sub_path = b.pathJoin(&output_components);
const output_sub_dir_path = switch (placeholder.tag) {
- .output_file => fs.path.dirname(output_sub_path).?,
+ .output_file => Dir.path.dirname(output_sub_path).?,
.output_directory => output_sub_path,
else => unreachable,
};
- b.cache_root.handle.makePath(output_sub_dir_path) catch |err| {
+ b.cache_root.handle.createDirPath(io, output_sub_dir_path) catch |err| {
return step.fail("unable to make path '{f}{s}': {s}", .{
b.cache_root, output_sub_dir_path, @errorName(err),
});
@@ -1022,7 +1025,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
try runCommand(run, argv_list.items, has_side_effects, tmp_dir_path, options, null);
- const dep_file_dir = std.fs.cwd();
+ const dep_file_dir = Dir.cwd();
const dep_file_basename = dep_output_file.generated_file.getPath2(b, step);
if (has_side_effects)
try man.addDepFile(dep_file_dir, dep_file_basename)
@@ -1039,29 +1042,23 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
// Rename into place
if (any_output) {
- const o_sub_path = "o" ++ fs.path.sep_str ++ &digest;
+ const o_sub_path = "o" ++ Dir.path.sep_str ++ &digest;
- b.cache_root.handle.rename(tmp_dir_path, o_sub_path) catch |err| {
+ b.cache_root.handle.rename(tmp_dir_path, b.cache_root.handle, o_sub_path, io) catch |err| {
if (err == error.PathAlreadyExists) {
- b.cache_root.handle.deleteTree(o_sub_path) catch |del_err| {
- return step.fail("unable to remove dir '{f}'{s}: {s}", .{
- b.cache_root,
- tmp_dir_path,
- @errorName(del_err),
+ b.cache_root.handle.deleteTree(io, o_sub_path) catch |del_err| {
+ return step.fail("unable to remove dir '{f}'{s}: {t}", .{
+ b.cache_root, tmp_dir_path, del_err,
});
};
- b.cache_root.handle.rename(tmp_dir_path, o_sub_path) catch |retry_err| {
- return step.fail("unable to rename dir '{f}{s}' to '{f}{s}': {s}", .{
- b.cache_root, tmp_dir_path,
- b.cache_root, o_sub_path,
- @errorName(retry_err),
+ b.cache_root.handle.rename(tmp_dir_path, b.cache_root.handle, o_sub_path, io) catch |retry_err| {
+ return step.fail("unable to rename dir '{f}{s}' to '{f}{s}': {t}", .{
+ b.cache_root, tmp_dir_path, b.cache_root, o_sub_path, retry_err,
});
};
} else {
- return step.fail("unable to rename dir '{f}{s}' to '{f}{s}': {s}", .{
- b.cache_root, tmp_dir_path,
- b.cache_root, o_sub_path,
- @errorName(err),
+ return step.fail("unable to rename dir '{f}{s}' to '{f}{s}': {t}", .{
+ b.cache_root, tmp_dir_path, b.cache_root, o_sub_path, err,
});
}
};
@@ -1110,8 +1107,8 @@ pub fn rerunInFuzzMode(
errdefer result.deinit();
result.writer.writeAll(file_plp.prefix) catch return error.OutOfMemory;
- const file = try file_path.root_dir.handle.openFile(file_path.subPathOrDot(), .{});
- defer file.close();
+ const file = try file_path.root_dir.handle.openFile(io, file_path.subPathOrDot(), .{});
+ defer file.close(io);
var buf: [1024]u8 = undefined;
var file_reader = file.reader(io, &buf);
@@ -1144,12 +1141,11 @@ pub fn rerunInFuzzMode(
const has_side_effects = false;
const rand_int = std.crypto.random.int(u64);
- const tmp_dir_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);
+ const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int);
try runCommand(run, argv_list.items, has_side_effects, tmp_dir_path, .{
.progress_node = prog_node,
.watch = undefined, // not used by `runCommand`
.web_server = null, // only needed for time reports
- .ttyconf = fuzz.ttyconf,
.unit_test_timeout_ns = null, // don't time out fuzz tests for now
.gpa = fuzz.gpa,
}, .{
@@ -1240,6 +1236,7 @@ fn runCommand(
const b = step.owner;
const arena = b.allocator;
const gpa = options.gpa;
+ const io = b.graph.io;
const cwd: ?[]const u8 = if (run.cwd) |lazy_cwd| lazy_cwd.getPath2(b, step) else null;
@@ -1260,33 +1257,6 @@ fn runCommand(
};
defer env_map.deinit();
- color: switch (run.color) {
- .manual => {},
- .enable => {
- try env_map.put("CLICOLOR_FORCE", "1");
- env_map.remove("NO_COLOR");
- },
- .disable => {
- try env_map.put("NO_COLOR", "1");
- env_map.remove("CLICOLOR_FORCE");
- },
- .inherit => switch (options.ttyconf) {
- .no_color, .windows_api => continue :color .disable,
- .escape_codes => continue :color .enable,
- },
- .auto => {
- const capture_stderr = run.captured_stderr != null or switch (run.stdio) {
- .check => |checks| checksContainStderr(checks.items),
- .infer_from_args, .inherit, .zig_test => false,
- };
- if (capture_stderr) {
- continue :color .disable;
- } else {
- continue :color .inherit;
- }
- },
- }
-
const opt_generic_result = spawnChildAndCollect(run, argv, &env_map, has_side_effects, options, fuzz_context) catch |err| term: {
// InvalidExe: cpu arch mismatch
// FileNotFound: can happen with a wrong dynamic linker path
@@ -1308,7 +1278,7 @@ fn runCommand(
const need_cross_libc = exe.is_linking_libc and
(root_target.isGnuLibC() or (root_target.isMuslLibC() and exe.linkage == .dynamic));
const other_target = exe.root_module.resolved_target.?.result;
- switch (std.zig.system.getExternalExecutor(&b.graph.host.result, &other_target, .{
+ switch (std.zig.system.getExternalExecutor(io, &b.graph.host.result, &other_target, .{
.qemu_fixes_dl = need_cross_libc and b.libc_runtimes_dir != null,
.link_libc = exe.is_linking_libc,
})) {
@@ -1468,8 +1438,8 @@ fn runCommand(
captured.output.generated_file.path = output_path;
const sub_path = b.pathJoin(&output_components);
- const sub_path_dirname = fs.path.dirname(sub_path).?;
- b.cache_root.handle.makePath(sub_path_dirname) catch |err| {
+ const sub_path_dirname = Dir.path.dirname(sub_path).?;
+ b.cache_root.handle.createDirPath(io, sub_path_dirname) catch |err| {
return step.fail("unable to make path '{f}{s}': {s}", .{
b.cache_root, sub_path_dirname, @errorName(err),
});
@@ -1480,7 +1450,7 @@ fn runCommand(
.leading => mem.trimStart(u8, stream.bytes.?, &std.ascii.whitespace),
.trailing => mem.trimEnd(u8, stream.bytes.?, &std.ascii.whitespace),
};
- b.cache_root.handle.writeFile(.{ .sub_path = sub_path, .data = data }) catch |err| {
+ b.cache_root.handle.writeFile(io, .{ .sub_path = sub_path, .data = data }) catch |err| {
return step.fail("unable to write file '{f}{s}': {s}", .{
b.cache_root, sub_path, @errorName(err),
});
@@ -1589,6 +1559,8 @@ fn spawnChildAndCollect(
) !?EvalGenericResult {
const b = run.step.owner;
const arena = b.allocator;
+ const graph = b.graph;
+ const io = graph.io;
if (fuzz_context != null) {
assert(!has_side_effects);
@@ -1654,8 +1626,12 @@ fn spawnChildAndCollect(
if (!run.disable_zig_progress and !inherit) {
child.progress_node = options.progress_node;
}
- if (inherit) std.debug.lockStdErr();
- defer if (inherit) std.debug.unlockStdErr();
+ const terminal_mode: Io.Terminal.Mode = if (inherit) m: {
+ const stderr = try io.lockStderr(&.{}, graph.stderr_mode);
+ break :m stderr.terminal_mode;
+ } else .no_color;
+ defer if (inherit) io.unlockStderr();
+ try setColorEnvironmentVariables(run, env_map, terminal_mode);
var timer = try std.time.Timer.start();
const res = try evalGeneric(run, &child);
run.step.result_duration_ns = timer.read();
@@ -1663,6 +1639,35 @@ fn spawnChildAndCollect(
}
}
+fn setColorEnvironmentVariables(run: *Run, env_map: *EnvMap, terminal_mode: Io.Terminal.Mode) !void {
+ color: switch (run.color) {
+ .manual => {},
+ .enable => {
+ try env_map.put("CLICOLOR_FORCE", "1");
+ env_map.remove("NO_COLOR");
+ },
+ .disable => {
+ try env_map.put("NO_COLOR", "1");
+ env_map.remove("CLICOLOR_FORCE");
+ },
+ .inherit => switch (terminal_mode) {
+ .no_color, .windows_api => continue :color .disable,
+ .escape_codes => continue :color .enable,
+ },
+ .auto => {
+ const capture_stderr = run.captured_stderr != null or switch (run.stdio) {
+ .check => |checks| checksContainStderr(checks.items),
+ .infer_from_args, .inherit, .zig_test => false,
+ };
+ if (capture_stderr) {
+ continue :color .disable;
+ } else {
+ continue :color .inherit;
+ }
+ },
+ }
+}
+
const StdioPollEnum = enum { stdout, stderr };
fn evalZigTest(
@@ -1671,8 +1676,10 @@ fn evalZigTest(
options: Step.MakeOptions,
fuzz_context: ?FuzzContext,
) !EvalZigTestResult {
- const gpa = run.step.owner.allocator;
- const arena = run.step.owner.allocator;
+ const step_owner = run.step.owner;
+ const gpa = step_owner.allocator;
+ const arena = step_owner.allocator;
+ const io = step_owner.graph.io;
// We will update this every time a child runs.
run.step.result_peak_rss = 0;
@@ -1691,14 +1698,14 @@ fn evalZigTest(
};
while (true) {
- try child.spawn();
+ try child.spawn(io);
var poller = std.Io.poll(gpa, StdioPollEnum, .{
.stdout = child.stdout.?,
.stderr = child.stderr.?,
});
var child_killed = false;
defer if (!child_killed) {
- _ = child.kill() catch {};
+ _ = child.kill(io) catch {};
poller.deinit();
run.step.result_peak_rss = @max(
run.step.result_peak_rss,
@@ -1724,11 +1731,11 @@ fn evalZigTest(
run.step.result_stderr = try arena.dupe(u8, poller.reader(.stderr).buffered());
// Clean up everything and wait for the child to exit.
- child.stdin.?.close();
+ child.stdin.?.close(io);
child.stdin = null;
poller.deinit();
child_killed = true;
- const term = try child.wait();
+ const term = try child.wait(io);
run.step.result_peak_rss = @max(
run.step.result_peak_rss,
child.resource_usage_statistics.getMaxRss() orelse 0,
@@ -1744,11 +1751,11 @@ fn evalZigTest(
poller.reader(.stderr).tossBuffered();
// Clean up everything and wait for the child to exit.
- child.stdin.?.close();
+ child.stdin.?.close(io);
child.stdin = null;
poller.deinit();
child_killed = true;
- const term = try child.wait();
+ const term = try child.wait(io);
run.step.result_peak_rss = @max(
run.step.result_peak_rss,
child.resource_usage_statistics.getMaxRss() orelse 0,
@@ -1836,6 +1843,7 @@ fn pollZigTest(
switch (ctx.fuzz.mode) {
.forever => {
sendRunFuzzTestMessage(
+ io,
child.stdin.?,
ctx.unit_test_index,
.forever,
@@ -1844,6 +1852,7 @@ fn pollZigTest(
},
.limit => |limit| {
sendRunFuzzTestMessage(
+ io,
child.stdin.?,
ctx.unit_test_index,
.iterations,
@@ -1853,11 +1862,11 @@ fn pollZigTest(
}
} else if (opt_metadata.*) |*md| {
// Previous unit test process died or was killed; we're continuing where it left off
- requestNextTest(child.stdin.?, md, &sub_prog_node) catch |err| return .{ .write_failed = err };
+ requestNextTest(io, child.stdin.?, md, &sub_prog_node) catch |err| return .{ .write_failed = err };
} else {
// Running unit tests normally
run.fuzz_tests.clearRetainingCapacity();
- sendMessage(child.stdin.?, .query_test_metadata) catch |err| return .{ .write_failed = err };
+ sendMessage(io, child.stdin.?, .query_test_metadata) catch |err| return .{ .write_failed = err };
}
var active_test_index: ?u32 = null;
@@ -1973,7 +1982,7 @@ fn pollZigTest(
active_test_index = null;
if (timer) |*t| t.reset();
- requestNextTest(child.stdin.?, &opt_metadata.*.?, &sub_prog_node) catch |err| return .{ .write_failed = err };
+ requestNextTest(io, child.stdin.?, &opt_metadata.*.?, &sub_prog_node) catch |err| return .{ .write_failed = err };
},
.test_started => {
active_test_index = opt_metadata.*.?.next_index - 1;
@@ -2022,7 +2031,7 @@ fn pollZigTest(
active_test_index = null;
if (timer) |*t| md.ns_per_test[tr_hdr.index] = t.lap();
- requestNextTest(child.stdin.?, md, &sub_prog_node) catch |err| return .{ .write_failed = err };
+ requestNextTest(io, child.stdin.?, md, &sub_prog_node) catch |err| return .{ .write_failed = err };
},
.coverage_id => {
coverage_id = body_r.takeInt(u64, .little) catch unreachable;
@@ -2093,7 +2102,7 @@ pub const CachedTestMetadata = struct {
}
};
-fn requestNextTest(in: fs.File, metadata: *TestMetadata, sub_prog_node: *?std.Progress.Node) !void {
+fn requestNextTest(io: Io, in: Io.File, metadata: *TestMetadata, sub_prog_node: *?std.Progress.Node) !void {
while (metadata.next_index < metadata.names.len) {
const i = metadata.next_index;
metadata.next_index += 1;
@@ -2104,31 +2113,31 @@ fn requestNextTest(in: fs.File, metadata: *TestMetadata, sub_prog_node: *?std.Pr
if (sub_prog_node.*) |n| n.end();
sub_prog_node.* = metadata.prog_node.start(name, 0);
- try sendRunTestMessage(in, .run_test, i);
+ try sendRunTestMessage(io, in, .run_test, i);
return;
} else {
metadata.next_index = std.math.maxInt(u32); // indicate that all tests are done
- try sendMessage(in, .exit);
+ try sendMessage(io, in, .exit);
}
}
-fn sendMessage(file: std.fs.File, tag: std.zig.Client.Message.Tag) !void {
+fn sendMessage(io: Io, file: Io.File, tag: std.zig.Client.Message.Tag) !void {
const header: std.zig.Client.Message.Header = .{
.tag = tag,
.bytes_len = 0,
};
- var w = file.writer(&.{});
+ var w = file.writer(io, &.{});
w.interface.writeStruct(header, .little) catch |err| switch (err) {
error.WriteFailed => return w.err.?,
};
}
-fn sendRunTestMessage(file: std.fs.File, tag: std.zig.Client.Message.Tag, index: u32) !void {
+fn sendRunTestMessage(io: Io, file: Io.File, tag: std.zig.Client.Message.Tag, index: u32) !void {
const header: std.zig.Client.Message.Header = .{
.tag = tag,
.bytes_len = 4,
};
- var w = file.writer(&.{});
+ var w = file.writer(io, &.{});
w.interface.writeStruct(header, .little) catch |err| switch (err) {
error.WriteFailed => return w.err.?,
};
@@ -2138,7 +2147,8 @@ fn sendRunTestMessage(file: std.fs.File, tag: std.zig.Client.Message.Tag, index:
}
fn sendRunFuzzTestMessage(
- file: std.fs.File,
+ io: Io,
+ file: Io.File,
index: u32,
kind: std.Build.abi.fuzz.LimitKind,
amount_or_instance: u64,
@@ -2147,7 +2157,7 @@ fn sendRunFuzzTestMessage(
.tag = .start_fuzzing,
.bytes_len = 4 + 1 + 8,
};
- var w = file.writer(&.{});
+ var w = file.writer(io, &.{});
w.interface.writeStruct(header, .little) catch |err| switch (err) {
error.WriteFailed => return w.err.?,
};
@@ -2167,30 +2177,30 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !EvalGenericResult {
const io = b.graph.io;
const arena = b.allocator;
- try child.spawn();
- errdefer _ = child.kill() catch {};
+ try child.spawn(io);
+ errdefer _ = child.kill(io) catch {};
try child.waitForSpawn();
switch (run.stdin) {
.bytes => |bytes| {
- child.stdin.?.writeAll(bytes) catch |err| {
- return run.step.fail("unable to write stdin: {s}", .{@errorName(err)});
+ child.stdin.?.writeStreamingAll(io, bytes) catch |err| {
+ return run.step.fail("unable to write stdin: {t}", .{err});
};
- child.stdin.?.close();
+ child.stdin.?.close(io);
child.stdin = null;
},
.lazy_path => |lazy_path| {
const path = lazy_path.getPath3(b, &run.step);
- const file = path.root_dir.handle.openFile(path.subPathOrDot(), .{}) catch |err| {
- return run.step.fail("unable to open stdin file: {s}", .{@errorName(err)});
+ const file = path.root_dir.handle.openFile(io, path.subPathOrDot(), .{}) catch |err| {
+ return run.step.fail("unable to open stdin file: {t}", .{err});
};
- defer file.close();
+ defer file.close(io);
// TODO https://github.com/ziglang/zig/issues/23955
var read_buffer: [1024]u8 = undefined;
var file_reader = file.reader(io, &read_buffer);
var write_buffer: [1024]u8 = undefined;
- var stdin_writer = child.stdin.?.writer(&write_buffer);
+ var stdin_writer = child.stdin.?.writer(io, &write_buffer);
_ = stdin_writer.interface.sendFileAll(&file_reader, .unlimited) catch |err| switch (err) {
error.ReadFailed => return run.step.fail("failed to read from {f}: {t}", .{
path, file_reader.err.?,
@@ -2204,7 +2214,7 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !EvalGenericResult {
stdin_writer.err.?,
}),
};
- child.stdin.?.close();
+ child.stdin.?.close(io);
child.stdin = null;
},
.none => {},
@@ -2263,7 +2273,7 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !EvalGenericResult {
run.step.result_peak_rss = child.resource_usage_statistics.getMaxRss() orelse 0;
return .{
- .term = try child.wait(),
+ .term = try child.wait(io),
.stdout = stdout_bytes,
.stderr = stderr_bytes,
};
@@ -2276,7 +2286,7 @@ fn addPathForDynLibs(run: *Run, artifact: *Step.Compile) void {
if (compile.root_module.resolved_target.?.result.os.tag == .windows and
compile.isDynamicLibrary())
{
- addPathDir(run, fs.path.dirname(compile.getEmittedBin().getPath2(b, &run.step)).?);
+ addPathDir(run, Dir.path.dirname(compile.getEmittedBin().getPath2(b, &run.step)).?);
}
}
}
diff --git a/lib/std/Build/Step/UpdateSourceFiles.zig b/lib/std/Build/Step/UpdateSourceFiles.zig
index 7cdb521d21..1c4c94f9cf 100644
--- a/lib/std/Build/Step/UpdateSourceFiles.zig
+++ b/lib/std/Build/Step/UpdateSourceFiles.zig
@@ -78,13 +78,13 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
var any_miss = false;
for (usf.output_source_files.items) |output_source_file| {
if (fs.path.dirname(output_source_file.sub_path)) |dirname| {
- b.build_root.handle.makePath(dirname) catch |err| {
+ b.build_root.handle.createDirPath(io, dirname) catch |err| {
return step.fail("unable to make path '{f}{s}': {t}", .{ b.build_root, dirname, err });
};
}
switch (output_source_file.contents) {
.bytes => |bytes| {
- b.build_root.handle.writeFile(.{ .sub_path = output_source_file.sub_path, .data = bytes }) catch |err| {
+ b.build_root.handle.writeFile(io, .{ .sub_path = output_source_file.sub_path, .data = bytes }) catch |err| {
return step.fail("unable to write file '{f}{s}': {t}", .{
b.build_root, output_source_file.sub_path, err,
});
@@ -99,7 +99,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
.cwd(),
io,
source_path,
- b.build_root.handle.adaptToNewApi(),
+ b.build_root.handle,
output_source_file.sub_path,
.{},
) catch |err| {
diff --git a/lib/std/Build/Step/WriteFile.zig b/lib/std/Build/Step/WriteFile.zig
index 030c7c6811..145c7f9bb3 100644
--- a/lib/std/Build/Step/WriteFile.zig
+++ b/lib/std/Build/Step/WriteFile.zig
@@ -206,9 +206,9 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
}
}
- const open_dir_cache = try arena.alloc(fs.Dir, write_file.directories.items.len);
+ const open_dir_cache = try arena.alloc(Io.Dir, write_file.directories.items.len);
var open_dirs_count: usize = 0;
- defer closeDirs(open_dir_cache[0..open_dirs_count]);
+ defer Io.Dir.closeMany(io, open_dir_cache[0..open_dirs_count]);
for (write_file.directories.items, open_dir_cache) |dir, *open_dir_cache_elem| {
man.hash.addBytes(dir.sub_path);
@@ -218,7 +218,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
const need_derived_inputs = try step.addDirectoryWatchInput(dir.source);
const src_dir_path = dir.source.getPath3(b, step);
- var src_dir = src_dir_path.root_dir.handle.openDir(src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| {
+ var src_dir = src_dir_path.root_dir.handle.openDir(io, src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| {
return step.fail("unable to open source directory '{f}': {s}", .{
src_dir_path, @errorName(err),
});
@@ -228,7 +228,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
var it = try src_dir.walk(gpa);
defer it.deinit();
- while (try it.next()) |entry| {
+ while (try it.next(io)) |entry| {
if (!dir.options.pathIncluded(entry.path)) continue;
switch (entry.kind) {
@@ -259,16 +259,13 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
write_file.generated_directory.path = try b.cache_root.join(arena, &.{ "o", &digest });
- var cache_dir = b.cache_root.handle.makeOpenPath(cache_path, .{}) catch |err| {
- return step.fail("unable to make path '{f}{s}': {s}", .{
- b.cache_root, cache_path, @errorName(err),
- });
- };
- defer cache_dir.close();
+ var cache_dir = b.cache_root.handle.createDirPathOpen(io, cache_path, .{}) catch |err|
+ return step.fail("unable to make path '{f}{s}': {t}", .{ b.cache_root, cache_path, err });
+ defer cache_dir.close(io);
for (write_file.files.items) |file| {
if (fs.path.dirname(file.sub_path)) |dirname| {
- cache_dir.makePath(dirname) catch |err| {
+ cache_dir.createDirPath(io, dirname) catch |err| {
return step.fail("unable to make path '{f}{s}{c}{s}': {t}", .{
b.cache_root, cache_path, fs.path.sep, dirname, err,
});
@@ -276,7 +273,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
}
switch (file.contents) {
.bytes => |bytes| {
- cache_dir.writeFile(.{ .sub_path = file.sub_path, .data = bytes }) catch |err| {
+ cache_dir.writeFile(io, .{ .sub_path = file.sub_path, .data = bytes }) catch |err| {
return step.fail("unable to write file '{f}{s}{c}{s}': {t}", .{
b.cache_root, cache_path, fs.path.sep, file.sub_path, err,
});
@@ -284,7 +281,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
},
.copy => |file_source| {
const source_path = file_source.getPath2(b, step);
- const prev_status = Io.Dir.updateFile(.cwd(), io, source_path, cache_dir.adaptToNewApi(), file.sub_path, .{}) catch |err| {
+ const prev_status = Io.Dir.updateFile(.cwd(), io, source_path, cache_dir, file.sub_path, .{}) catch |err| {
return step.fail("unable to update file from '{s}' to '{f}{s}{c}{s}': {t}", .{
source_path, b.cache_root, cache_path, fs.path.sep, file.sub_path, err,
});
@@ -303,7 +300,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
const dest_dirname = dir.sub_path;
if (dest_dirname.len != 0) {
- cache_dir.makePath(dest_dirname) catch |err| {
+ cache_dir.createDirPath(io, dest_dirname) catch |err| {
return step.fail("unable to make path '{f}{s}{c}{s}': {s}", .{
b.cache_root, cache_path, fs.path.sep, dest_dirname, @errorName(err),
});
@@ -312,19 +309,19 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
var it = try already_open_dir.walk(gpa);
defer it.deinit();
- while (try it.next()) |entry| {
+ while (try it.next(io)) |entry| {
if (!dir.options.pathIncluded(entry.path)) continue;
const src_entry_path = try src_dir_path.join(arena, entry.path);
const dest_path = b.pathJoin(&.{ dest_dirname, entry.path });
switch (entry.kind) {
- .directory => try cache_dir.makePath(dest_path),
+ .directory => try cache_dir.createDirPath(io, dest_path),
.file => {
const prev_status = Io.Dir.updateFile(
- src_entry_path.root_dir.handle.adaptToNewApi(),
+ src_entry_path.root_dir.handle,
io,
src_entry_path.sub_path,
- cache_dir.adaptToNewApi(),
+ cache_dir,
dest_path,
.{},
) catch |err| {
@@ -341,7 +338,3 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
try step.writeManifest(&man);
}
-
-fn closeDirs(dirs: []fs.Dir) void {
- for (dirs) |*d| d.close();
-}
diff --git a/lib/std/Build/Watch.zig b/lib/std/Build/Watch.zig
index ca01376e02..9042241b55 100644
--- a/lib/std/Build/Watch.zig
+++ b/lib/std/Build/Watch.zig
@@ -122,7 +122,7 @@ const Os = switch (builtin.os.tag) {
}) catch return error.NameTooLong;
const stack_ptr: *std.os.linux.file_handle = @ptrCast(&file_handle_buffer);
stack_ptr.handle_bytes = file_handle_buffer.len - @sizeOf(std.os.linux.file_handle);
- try posix.name_to_handle_at(path.root_dir.handle.fd, adjusted_path, stack_ptr, mount_id, std.os.linux.AT.HANDLE_FID);
+ try posix.name_to_handle_at(path.root_dir.handle.handle, adjusted_path, stack_ptr, mount_id, std.os.linux.AT.HANDLE_FID);
const stack_lfh: FileHandle = .{ .handle = stack_ptr };
return stack_lfh.clone(gpa);
}
@@ -222,7 +222,7 @@ const Os = switch (builtin.os.tag) {
posix.fanotify_mark(fan_fd, .{
.ADD = true,
.ONLYDIR = true,
- }, fan_mask, path.root_dir.handle.fd, path.subPathOrDot()) catch |err| {
+ }, fan_mask, path.root_dir.handle.handle, path.subPathOrDot()) catch |err| {
fatal("unable to watch {f}: {s}", .{ path, @errorName(err) });
};
}
@@ -275,7 +275,7 @@ const Os = switch (builtin.os.tag) {
posix.fanotify_mark(fan_fd, .{
.REMOVE = true,
.ONLYDIR = true,
- }, fan_mask, path.root_dir.handle.fd, path.subPathOrDot()) catch |err| switch (err) {
+ }, fan_mask, path.root_dir.handle.handle, path.subPathOrDot()) catch |err| switch (err) {
error.FileNotFound => {}, // Expected, harmless.
else => |e| std.log.warn("unable to unwatch '{f}': {s}", .{ path, @errorName(e) }),
};
@@ -350,10 +350,10 @@ const Os = switch (builtin.os.tag) {
}
fn init(gpa: Allocator, path: Cache.Path) !*@This() {
- // The following code is a drawn out NtCreateFile call. (mostly adapted from std.fs.Dir.makeOpenDirAccessMaskW)
+ // The following code is a drawn out NtCreateFile call. (mostly adapted from Io.Dir.makeOpenDirAccessMaskW)
// It's necessary in order to get the specific flags that are required when calling ReadDirectoryChangesW.
var dir_handle: windows.HANDLE = undefined;
- const root_fd = path.root_dir.handle.fd;
+ const root_fd = path.root_dir.handle.handle;
const sub_path = path.subPathOrDot();
const sub_path_w = try windows.sliceToPrefixedFileW(root_fd, sub_path);
const path_len_bytes = std.math.cast(u16, sub_path_w.len * 2) orelse return error.NameTooLong;
@@ -681,10 +681,10 @@ const Os = switch (builtin.os.tag) {
if (!gop.found_existing) {
const skip_open_dir = path.sub_path.len == 0;
const dir_fd = if (skip_open_dir)
- path.root_dir.handle.fd
+ path.root_dir.handle.handle
else
- posix.openat(path.root_dir.handle.fd, path.sub_path, dir_open_flags, 0) catch |err| {
- fatal("failed to open directory {f}: {s}", .{ path, @errorName(err) });
+ posix.openat(path.root_dir.handle.handle, path.sub_path, dir_open_flags, 0) catch |err| {
+ fatal("failed to open directory {f}: {t}", .{ path, err });
};
// Empirically the dir has to stay open or else no events are triggered.
errdefer if (!skip_open_dir) posix.close(dir_fd);
@@ -750,7 +750,7 @@ const Os = switch (builtin.os.tag) {
// to access that data via the dir_fd field.
const path = w.dir_table.keys()[i];
const dir_fd = if (path.sub_path.len == 0)
- path.root_dir.handle.fd
+ path.root_dir.handle.handle
else
handles.items(.dir_fd)[i];
assert(dir_fd != -1);
@@ -761,7 +761,7 @@ const Os = switch (builtin.os.tag) {
const last_dir_fd = fd: {
const last_path = w.dir_table.keys()[handles.len - 1];
const last_dir_fd = if (last_path.sub_path.len == 0)
- last_path.root_dir.handle.fd
+ last_path.root_dir.handle.handle
else
handles.items(.dir_fd)[handles.len - 1];
assert(last_dir_fd != -1);
diff --git a/lib/std/Build/Watch/FsEvents.zig b/lib/std/Build/Watch/FsEvents.zig
index 6131663993..2a48534b3a 100644
--- a/lib/std/Build/Watch/FsEvents.zig
+++ b/lib/std/Build/Watch/FsEvents.zig
@@ -102,10 +102,10 @@ pub fn init() error{ OpenFrameworkFailed, MissingCoreServicesSymbol }!FsEvents {
};
}
-pub fn deinit(fse: *FsEvents, gpa: Allocator) void {
+pub fn deinit(fse: *FsEvents, gpa: Allocator, io: Io) void {
dispatch_release(fse.waiting_semaphore);
dispatch_release(fse.dispatch_queue);
- fse.core_services.close();
+ fse.core_services.close(io);
gpa.free(fse.watch_roots);
fse.watch_paths.deinit(gpa);
@@ -487,6 +487,7 @@ const FSEventStreamEventFlags = packed struct(u32) {
};
const std = @import("std");
+const Io = std.Io;
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const watch_log = std.log.scoped(.watch);
diff --git a/lib/std/Build/WebServer.zig b/lib/std/Build/WebServer.zig
index 2c865a8889..a2b35e3522 100644
--- a/lib/std/Build/WebServer.zig
+++ b/lib/std/Build/WebServer.zig
@@ -2,7 +2,6 @@ gpa: Allocator,
graph: *const Build.Graph,
all_steps: []const *Build.Step,
listen_address: net.IpAddress,
-ttyconf: Io.tty.Config,
root_prog_node: std.Progress.Node,
watch: bool,
@@ -52,7 +51,6 @@ pub fn notifyUpdate(ws: *WebServer) void {
pub const Options = struct {
gpa: Allocator,
- ttyconf: Io.tty.Config,
graph: *const std.Build.Graph,
all_steps: []const *Build.Step,
root_prog_node: std.Progress.Node,
@@ -98,7 +96,6 @@ pub fn init(opts: Options) WebServer {
return .{
.gpa = opts.gpa,
- .ttyconf = opts.ttyconf,
.graph = opts.graph,
.all_steps = all_steps,
.listen_address = opts.listen_address,
@@ -129,6 +126,7 @@ pub fn init(opts: Options) WebServer {
}
pub fn deinit(ws: *WebServer) void {
const gpa = ws.gpa;
+ const io = ws.graph.io;
gpa.free(ws.step_names_trailing);
gpa.free(ws.step_status_bits);
@@ -139,7 +137,7 @@ pub fn deinit(ws: *WebServer) void {
gpa.free(ws.time_report_update_times);
if (ws.serve_thread) |t| {
- if (ws.tcp_server) |*s| s.stream.close();
+ if (ws.tcp_server) |*s| s.stream.close(io);
t.join();
}
if (ws.tcp_server) |*s| s.deinit();
@@ -217,9 +215,9 @@ pub fn finishBuild(ws: *WebServer, opts: struct {
else => {},
}
if (@bitSizeOf(usize) != 64) {
- // Current implementation depends on posix.mmap()'s second parameter, `length: usize`,
- // being compatible with `std.fs.getEndPos() u64`'s return value. This is not the case
- // on 32-bit platforms.
+ // Current implementation depends on posix.mmap()'s second
+ // parameter, `length: usize`, being compatible with file system's
+ // u64 return value. This is not the case on 32-bit platforms.
// Affects or affected by issues #5185, #22523, and #22464.
std.process.fatal("--fuzz not yet implemented on {d}-bit platforms", .{@bitSizeOf(usize)});
}
@@ -232,7 +230,6 @@ pub fn finishBuild(ws: *WebServer, opts: struct {
ws.fuzz = Fuzz.init(
ws.gpa,
ws.graph.io,
- ws.ttyconf,
ws.all_steps,
ws.root_prog_node,
.{ .forever = .{ .ws = ws } },
@@ -468,11 +465,12 @@ pub fn serveFile(
content_type: []const u8,
) !void {
const gpa = ws.gpa;
+ const io = ws.graph.io;
// The desired API is actually sendfile, which will require enhancing http.Server.
// We load the file with every request so that the user can make changes to the file
// and refresh the HTML page without restarting this server.
- const file_contents = path.root_dir.handle.readFileAlloc(path.sub_path, gpa, .limited(10 * 1024 * 1024)) catch |err| {
- log.err("failed to read '{f}': {s}", .{ path, @errorName(err) });
+ const file_contents = path.root_dir.handle.readFileAlloc(io, path.sub_path, gpa, .limited(10 * 1024 * 1024)) catch |err| {
+ log.err("failed to read '{f}': {t}", .{ path, err });
return error.AlreadyReported;
};
defer gpa.free(file_contents);
@@ -503,14 +501,14 @@ pub fn serveTarFile(ws: *WebServer, request: *http.Server.Request, paths: []cons
var archiver: std.tar.Writer = .{ .underlying_writer = &response.writer };
for (paths) |path| {
- var file = path.root_dir.handle.openFile(path.sub_path, .{}) catch |err| {
+ var file = path.root_dir.handle.openFile(io, path.sub_path, .{}) catch |err| {
log.err("failed to open '{f}': {s}", .{ path, @errorName(err) });
continue;
};
- defer file.close();
- const stat = try file.stat();
+ defer file.close(io);
+ const stat = try file.stat(io);
var read_buffer: [1024]u8 = undefined;
- var file_reader: Io.File.Reader = .initSize(file.adaptToNewApi(), io, &read_buffer, stat.size);
+ var file_reader: Io.File.Reader = .initSize(file, io, &read_buffer, stat.size);
// TODO: this logic is completely bogus -- obviously so, because `path.root_dir.path` can
// be cwd-relative. This is also related to why linkification doesn't work in the fuzzer UI:
@@ -578,7 +576,7 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim
child.stdin_behavior = .Pipe;
child.stdout_behavior = .Pipe;
child.stderr_behavior = .Pipe;
- try child.spawn();
+ try child.spawn(io);
var poller = Io.poll(gpa, enum { stdout, stderr }, .{
.stdout = child.stdout.?,
@@ -586,7 +584,7 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim
});
defer poller.deinit();
- try child.stdin.?.writeAll(@ptrCast(@as([]const std.zig.Client.Message.Header, &.{
+ try child.stdin.?.writeStreamingAll(io, @ptrCast(@as([]const std.zig.Client.Message.Header, &.{
.{ .tag = .update, .bytes_len = 0 },
.{ .tag = .exit, .bytes_len = 0 },
})));
@@ -634,10 +632,10 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim
}
// Send EOF to stdin.
- child.stdin.?.close();
+ child.stdin.?.close(io);
child.stdin = null;
- switch (try child.wait()) {
+ switch (try child.wait(io)) {
.Exited => |code| {
if (code != 0) {
log.err(
@@ -657,7 +655,7 @@ fn buildClientWasm(ws: *WebServer, arena: Allocator, optimize: std.builtin.Optim
}
if (result_error_bundle.errorMessageCount() > 0) {
- result_error_bundle.renderToStdErr(.{}, .auto);
+ try result_error_bundle.renderToStderr(io, .{}, .auto);
log.err("the following command failed with {d} compilation errors:\n{s}", .{
result_error_bundle.errorMessageCount(),
try Build.Step.allocPrintCmd(arena, null, argv.items),