update std.process.Child.run occurences to use io

This commit is contained in:
Andrew Kelley
2025-12-08 18:46:55 -08:00
parent 9e3bda5eff
commit 3725f72293
10 changed files with 115 additions and 135 deletions
+5 -6
View File
@@ -78,7 +78,7 @@ pub fn main() !void {
if (input_file) |libc_file| {
const libc = try arena.create(LibCInstallation);
libc.* = LibCInstallation.parse(arena, libc_file, &target) catch |err| {
fatal("unable to parse libc file at path {s}: {s}", .{ libc_file, @errorName(err) });
fatal("unable to parse libc file at path {s}: {t}", .{ libc_file, err });
};
break :libc libc;
} else {
@@ -97,7 +97,7 @@ pub fn main() !void {
libc_installation,
) catch |err| {
const zig_target = try target.zigTriple(arena);
fatal("unable to detect libc for target {s}: {s}", .{ zig_target, @errorName(err) });
fatal("unable to detect libc for target {s}: {t}", .{ zig_target, err });
};
if (libc_dirs.libc_include_dir_list.len == 0) {
@@ -115,19 +115,18 @@ pub fn main() !void {
if (input_file) |libc_file| {
var libc = LibCInstallation.parse(gpa, libc_file, &target) catch |err| {
fatal("unable to parse libc file at path {s}: {s}", .{ libc_file, @errorName(err) });
fatal("unable to parse libc file at path {s}: {t}", .{ libc_file, err });
};
defer libc.deinit(gpa);
} else {
if (!target_query.canDetectLibC()) {
fatal("unable to detect libc for non-native target", .{});
}
var libc = LibCInstallation.findNative(.{
.allocator = gpa,
var libc = LibCInstallation.findNative(gpa, io, .{
.verbose = true,
.target = &target,
}) catch |err| {
fatal("unable to detect native libc: {s}", .{@errorName(err)});
fatal("unable to detect native libc: {t}", .{err});
};
defer libc.deinit(gpa);
+2 -5
View File
@@ -307,11 +307,8 @@ fn termToInteresting(term: std.process.Child.Term) Interestingness {
};
}
fn runCheck(arena: std.mem.Allocator, argv: []const []const u8) !Interestingness {
const result = try std.process.Child.run(.{
.allocator = arena,
.argv = argv,
});
fn runCheck(arena: Allocator, io: Io, argv: []const []const u8) !Interestingness {
const result = try std.process.Child.run(arena, io, .{ .argv = argv });
if (result.stderr.len != 0)
std.debug.print("{s}", .{result.stderr});
return termToInteresting(result.term);
+2 -2
View File
@@ -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 });
+48 -70
View File
@@ -166,8 +166,6 @@ pub fn render(self: LibCInstallation, out: *std.Io.Writer) !void {
}
pub const FindNativeOptions = struct {
allocator: Allocator,
io: Io,
target: *const std.Target,
/// If enabled, will print human-friendly errors to stderr.
@@ -175,10 +173,7 @@ pub const FindNativeOptions = struct {
};
/// Finds the default, native libc.
pub fn findNative(args: FindNativeOptions) FindError!LibCInstallation {
const gpa = args.allocator;
const io = args.io;
pub fn findNative(gpa: Allocator, io: Io, args: FindNativeOptions) FindError!LibCInstallation {
var self: LibCInstallation = .{};
if (is_darwin and args.target.os.tag.isDarwin()) {
@@ -203,14 +198,14 @@ pub fn findNative(args: FindNativeOptions) FindError!LibCInstallation {
};
defer sdk.free(gpa);
try self.findNativeMsvcIncludeDir(args, sdk);
try self.findNativeMsvcLibDir(args, sdk);
try self.findNativeKernel32LibDir(args, sdk);
try self.findNativeIncludeDirWindows(args, sdk);
try self.findNativeCrtDirWindows(args, sdk);
try self.findNativeMsvcIncludeDir(gpa, io, sdk);
try self.findNativeMsvcLibDir(gpa, sdk);
try self.findNativeKernel32LibDir(gpa, io, args, sdk);
try self.findNativeIncludeDirWindows(gpa, io, args, sdk);
try self.findNativeCrtDirWindows(gpa, io, args.target, sdk);
} else if (is_haiku) {
try self.findNativeIncludeDirPosix(args);
try self.findNativeGccDirHaiku(args);
try self.findNativeGccDirHaiku(gpa, io, args);
self.crt_dir = try gpa.dupeZ(u8, "/system/develop/lib");
} else if (builtin.target.os.tag == .illumos) {
// There is only one libc, and its headers/libraries are always in the same spot.
@@ -221,7 +216,7 @@ pub fn findNative(args: FindNativeOptions) FindError!LibCInstallation {
try self.findNativeIncludeDirPosix(args);
switch (builtin.target.os.tag) {
.freebsd, .netbsd, .openbsd, .dragonfly => self.crt_dir = try gpa.dupeZ(u8, "/usr/lib"),
.linux => try self.findNativeCrtDirPosix(args),
.linux => try self.findNativeCrtDirPosix(gpa, io, args),
else => {},
}
} else {
@@ -241,12 +236,9 @@ pub fn deinit(self: *LibCInstallation, allocator: Allocator) void {
self.* = undefined;
}
fn findNativeIncludeDirPosix(self: *LibCInstallation, args: FindNativeOptions) FindError!void {
const allocator = args.allocator;
const io = args.io;
fn findNativeIncludeDirPosix(self: *LibCInstallation, gpa: Allocator, io: Io, args: FindNativeOptions) FindError!void {
// Detect infinite loops.
var env_map = std.process.getEnvMap(allocator) catch |err| switch (err) {
var env_map = std.process.getEnvMap(gpa) catch |err| switch (err) {
error.Unexpected => unreachable, // WASI-only
else => |e| return e,
};
@@ -265,7 +257,7 @@ fn findNativeIncludeDirPosix(self: *LibCInstallation, args: FindNativeOptions) F
const dev_null = if (is_windows) "nul" else "/dev/null";
var argv = std.array_list.Managed([]const u8).init(allocator);
var argv = std.array_list.Managed([]const u8).init(gpa);
defer argv.deinit();
try appendCcExe(&argv, skip_cc_env_var);
@@ -276,8 +268,7 @@ fn findNativeIncludeDirPosix(self: *LibCInstallation, args: FindNativeOptions) F
dev_null,
});
const run_res = std.process.Child.run(.{
.allocator = allocator,
const run_res = std.process.Child.run(gpa, io, .{
.argv = argv.items,
.max_output_bytes = 1024 * 1024,
.env_map = &env_map,
@@ -294,8 +285,8 @@ fn findNativeIncludeDirPosix(self: *LibCInstallation, args: FindNativeOptions) F
},
};
defer {
allocator.free(run_res.stdout);
allocator.free(run_res.stderr);
gpa.free(run_res.stdout);
gpa.free(run_res.stderr);
}
switch (run_res.term) {
.Exited => |code| if (code != 0) {
@@ -309,7 +300,7 @@ fn findNativeIncludeDirPosix(self: *LibCInstallation, args: FindNativeOptions) F
}
var it = std.mem.tokenizeAny(u8, run_res.stderr, "\n\r");
var search_paths = std.array_list.Managed([]const u8).init(allocator);
var search_paths = std.array_list.Managed([]const u8).init(gpa);
defer search_paths.deinit();
while (it.next()) |line| {
if (line.len != 0 and line[0] == ' ') {
@@ -345,7 +336,7 @@ fn findNativeIncludeDirPosix(self: *LibCInstallation, args: FindNativeOptions) F
if (self.include_dir == null) {
if (search_dir.access(include_dir_example_file, .{})) |_| {
self.include_dir = try allocator.dupeZ(u8, search_path);
self.include_dir = try gpa.dupeZ(u8, search_path);
} else |err| switch (err) {
error.FileNotFound => {},
else => return error.FileSystem,
@@ -354,7 +345,7 @@ fn findNativeIncludeDirPosix(self: *LibCInstallation, args: FindNativeOptions) F
if (self.sys_include_dir == null) {
if (search_dir.access(io, sys_include_dir_example_file, .{})) |_| {
self.sys_include_dir = try allocator.dupeZ(u8, search_path);
self.sys_include_dir = try gpa.dupeZ(u8, search_path);
} else |err| switch (err) {
error.FileNotFound => {},
else => return error.FileSystem,
@@ -372,16 +363,14 @@ fn findNativeIncludeDirPosix(self: *LibCInstallation, args: FindNativeOptions) F
fn findNativeIncludeDirWindows(
self: *LibCInstallation,
args: FindNativeOptions,
gpa: Allocator,
io: Io,
sdk: std.zig.WindowsSdk,
) FindError!void {
const allocator = args.allocator;
const io = args.io;
var install_buf: [2]std.zig.WindowsSdk.Installation = undefined;
const installs = fillInstallations(&install_buf, sdk);
var result_buf = std.array_list.Managed(u8).init(allocator);
var result_buf = std.array_list.Managed(u8).init(gpa);
defer result_buf.deinit();
for (installs) |install| {
@@ -412,19 +401,18 @@ fn findNativeIncludeDirWindows(
fn findNativeCrtDirWindows(
self: *LibCInstallation,
args: FindNativeOptions,
gpa: Allocator,
io: Io,
target: *const std.Target,
sdk: std.zig.WindowsSdk,
) FindError!void {
const allocator = args.allocator;
const io = args.io;
var install_buf: [2]std.zig.WindowsSdk.Installation = undefined;
const installs = fillInstallations(&install_buf, sdk);
var result_buf = std.array_list.Managed(u8).init(allocator);
var result_buf = std.array_list.Managed(u8).init(gpa);
defer result_buf.deinit();
const arch_sub_dir = switch (args.target.cpu.arch) {
const arch_sub_dir = switch (target.cpu.arch) {
.x86 => "x86",
.x86_64 => "x64",
.arm, .armeb => "arm",
@@ -457,9 +445,8 @@ fn findNativeCrtDirWindows(
return error.LibCRuntimeNotFound;
}
fn findNativeCrtDirPosix(self: *LibCInstallation, args: FindNativeOptions) FindError!void {
self.crt_dir = try ccPrintFileName(.{
.allocator = args.allocator,
fn findNativeCrtDirPosix(self: *LibCInstallation, gpa: Allocator, io: Io, args: FindNativeOptions) FindError!void {
self.crt_dir = try ccPrintFileName(gpa, io, .{
.search_basename = switch (args.target.os.tag) {
.linux => if (args.target.abi.isAndroid()) "crtbegin_dynamic.o" else "crt1.o",
else => "crt1.o",
@@ -469,9 +456,8 @@ fn findNativeCrtDirPosix(self: *LibCInstallation, args: FindNativeOptions) FindE
});
}
fn findNativeGccDirHaiku(self: *LibCInstallation, args: FindNativeOptions) FindError!void {
self.gcc_dir = try ccPrintFileName(.{
.allocator = args.allocator,
fn findNativeGccDirHaiku(self: *LibCInstallation, gpa: Allocator, io: Io, args: FindNativeOptions) FindError!void {
self.gcc_dir = try ccPrintFileName(gpa, io, .{
.search_basename = "crtbeginS.o",
.want_dirname = .only_dir,
.verbose = args.verbose,
@@ -480,16 +466,15 @@ fn findNativeGccDirHaiku(self: *LibCInstallation, args: FindNativeOptions) FindE
fn findNativeKernel32LibDir(
self: *LibCInstallation,
gpa: Allocator,
io: Io,
args: FindNativeOptions,
sdk: std.zig.WindowsSdk,
) FindError!void {
const allocator = args.allocator;
const io = args.io;
var install_buf: [2]std.zig.WindowsSdk.Installation = undefined;
const installs = fillInstallations(&install_buf, sdk);
var result_buf = std.array_list.Managed(u8).init(allocator);
var result_buf = std.array_list.Managed(u8).init(gpa);
defer result_buf.deinit();
const arch_sub_dir = switch (args.target.cpu.arch) {
@@ -527,18 +512,16 @@ fn findNativeKernel32LibDir(
fn findNativeMsvcIncludeDir(
self: *LibCInstallation,
args: FindNativeOptions,
gpa: Allocator,
io: Io,
sdk: std.zig.WindowsSdk,
) FindError!void {
const allocator = args.allocator;
const io = args.io;
const msvc_lib_dir = sdk.msvc_lib_dir orelse return error.LibCStdLibHeaderNotFound;
const up1 = fs.path.dirname(msvc_lib_dir) orelse return error.LibCStdLibHeaderNotFound;
const up2 = fs.path.dirname(up1) orelse return error.LibCStdLibHeaderNotFound;
const dir_path = try fs.path.join(allocator, &[_][]const u8{ up2, "include" });
errdefer allocator.free(dir_path);
const dir_path = try fs.path.join(gpa, &[_][]const u8{ up2, "include" });
errdefer gpa.free(dir_path);
var dir = Io.Dir.cwd().openDir(io, dir_path, .{}) catch |err| switch (err) {
error.FileNotFound,
@@ -560,27 +543,23 @@ fn findNativeMsvcIncludeDir(
fn findNativeMsvcLibDir(
self: *LibCInstallation,
args: FindNativeOptions,
gpa: Allocator,
sdk: std.zig.WindowsSdk,
) FindError!void {
const allocator = args.allocator;
const msvc_lib_dir = sdk.msvc_lib_dir orelse return error.LibCRuntimeNotFound;
self.msvc_lib_dir = try allocator.dupe(u8, msvc_lib_dir);
self.msvc_lib_dir = try gpa.dupe(u8, msvc_lib_dir);
}
pub const CCPrintFileNameOptions = struct {
allocator: Allocator,
search_basename: []const u8,
want_dirname: enum { full_path, only_dir },
verbose: bool = false,
};
/// caller owns returned memory
fn ccPrintFileName(args: CCPrintFileNameOptions) ![:0]u8 {
const allocator = args.allocator;
fn ccPrintFileName(gpa: Allocator, io: Io, args: CCPrintFileNameOptions) ![:0]u8 {
// Detect infinite loops.
var env_map = std.process.getEnvMap(allocator) catch |err| switch (err) {
var env_map = std.process.getEnvMap(gpa) catch |err| switch (err) {
error.Unexpected => unreachable, // WASI-only
else => |e| return e,
};
@@ -597,17 +576,16 @@ fn ccPrintFileName(args: CCPrintFileNameOptions) ![:0]u8 {
break :blk false;
};
var argv = std.array_list.Managed([]const u8).init(allocator);
var argv = std.array_list.Managed([]const u8).init(gpa);
defer argv.deinit();
const arg1 = try std.fmt.allocPrint(allocator, "-print-file-name={s}", .{args.search_basename});
defer allocator.free(arg1);
const arg1 = try std.fmt.allocPrint(gpa, "-print-file-name={s}", .{args.search_basename});
defer gpa.free(arg1);
try appendCcExe(&argv, skip_cc_env_var);
try argv.append(arg1);
const run_res = std.process.Child.run(.{
.allocator = allocator,
const run_res = std.process.Child.run(gpa, io, .{
.argv = argv.items,
.max_output_bytes = 1024 * 1024,
.env_map = &env_map,
@@ -621,8 +599,8 @@ fn ccPrintFileName(args: CCPrintFileNameOptions) ![:0]u8 {
else => return error.UnableToSpawnCCompiler,
};
defer {
allocator.free(run_res.stdout);
allocator.free(run_res.stderr);
gpa.free(run_res.stdout);
gpa.free(run_res.stderr);
}
switch (run_res.term) {
.Exited => |code| if (code != 0) {
@@ -641,10 +619,10 @@ fn ccPrintFileName(args: CCPrintFileNameOptions) ![:0]u8 {
// So we detect failure by checking if the output matches exactly the input.
if (std.mem.eql(u8, line, args.search_basename)) return error.LibCRuntimeNotFound;
switch (args.want_dirname) {
.full_path => return allocator.dupeZ(u8, line),
.full_path => return gpa.dupeZ(u8, line),
.only_dir => {
const dirname = fs.path.dirname(line) orelse return error.LibCRuntimeNotFound;
return allocator.dupeZ(u8, dirname);
return gpa.dupeZ(u8, dirname);
},
}
}
+15 -14
View File
@@ -1,28 +1,29 @@
const std = @import("std");
const Io = std.Io;
const mem = std.mem;
const Allocator = mem.Allocator;
const Allocator = std.mem.Allocator;
const Target = std.Target;
const Version = std.SemanticVersion;
pub const macos = @import("darwin/macos.zig");
/// Check if SDK is installed on Darwin without triggering CLT installation popup window.
/// Note: simply invoking `xcrun` will inevitably trigger the CLT installation popup.
///
/// Simply invoking `xcrun` will inevitably trigger the CLT installation popup.
/// Therefore, we resort to invoking `xcode-select --print-path` and checking
/// if the status is nonzero.
///
/// stderr from xcode-select is ignored.
///
/// If error.OutOfMemory occurs in Allocator, this function returns null.
pub fn isSdkInstalled(allocator: Allocator) bool {
const result = std.process.Child.run(.{
.allocator = allocator,
pub fn isSdkInstalled(gpa: Allocator, io: Io) bool {
const result = std.process.Child.run(gpa, io, .{
.argv = &.{ "xcode-select", "--print-path" },
}) catch return false;
defer {
allocator.free(result.stderr);
allocator.free(result.stdout);
gpa.free(result.stderr);
gpa.free(result.stdout);
}
return switch (result.term) {
.Exited => |code| if (code == 0) result.stdout.len > 0 else false,
else => false,
@@ -34,7 +35,7 @@ pub fn isSdkInstalled(allocator: Allocator) bool {
/// Caller owns the memory.
/// stderr from xcrun is ignored.
/// If error.OutOfMemory occurs in Allocator, this function returns null.
pub fn getSdk(allocator: Allocator, target: *const Target) ?[]const u8 {
pub fn getSdk(gpa: Allocator, io: Io, target: *const Target) ?[]const u8 {
const is_simulator_abi = target.abi == .simulator;
const sdk = switch (target.os.tag) {
.driverkit => "driverkit",
@@ -46,16 +47,16 @@ pub fn getSdk(allocator: Allocator, target: *const Target) ?[]const u8 {
else => return null,
};
const argv = &[_][]const u8{ "xcrun", "--sdk", sdk, "--show-sdk-path" };
const result = std.process.Child.run(.{ .allocator = allocator, .argv = argv }) catch return null;
const result = std.process.Child.run(gpa, io, .{ .argv = argv }) catch return null;
defer {
allocator.free(result.stderr);
allocator.free(result.stdout);
gpa.free(result.stderr);
gpa.free(result.stdout);
}
switch (result.term) {
.Exited => |code| if (code != 0) return null,
else => return null,
}
return allocator.dupe(u8, mem.trimEnd(u8, result.stdout, "\r\n")) catch null;
return gpa.dupe(u8, mem.trimEnd(u8, result.stdout, "\r\n")) catch null;
}
test {
+1 -2
View File
@@ -4017,8 +4017,7 @@ fn createModule(
any_name_queries_remaining)
{
if (create_module.libc_installation == null) {
create_module.libc_installation = LibCInstallation.findNative(.{
.allocator = arena,
create_module.libc_installation = LibCInstallation.findNative(arena, io, .{
.verbose = true,
.target = target,
}) catch |err| {
+1 -1
View File
@@ -57,7 +57,7 @@ pub fn main() !void {
// Check that FileNotFound is consistent across platforms when trying to spawn an executable that doesn't exist
const missing_child_path = try std.mem.concat(gpa, u8, &.{ child_path, "_intentionally_missing" });
defer gpa.free(missing_child_path);
try std.testing.expectError(error.FileNotFound, std.process.Child.run(.{ .allocator = gpa, .argv = &.{missing_child_path} }));
try std.testing.expectError(error.FileNotFound, std.process.Child.run(gpa, io, .{ .argv = &.{missing_child_path} }));
}
var parent_test_error = false;
+9 -8
View File
@@ -1,5 +1,7 @@
const std = @import("std");
const builtin = @import("builtin");
const std = @import("std");
const Io = std.Io;
const Allocator = std.mem.Allocator;
pub fn main() anyerror!void {
@@ -78,13 +80,13 @@ pub fn main() anyerror!void {
}
}
fn testExec(gpa: std.mem.Allocator, args: []const []const u8, env: ?*std.process.EnvMap) !void {
try testExecBat(gpa, "args1.bat", args, env);
try testExecBat(gpa, "args2.bat", args, env);
try testExecBat(gpa, "args3.bat", args, env);
fn testExec(gpa: Allocator, io: Io, args: []const []const u8, env: ?*std.process.EnvMap) !void {
try testExecBat(gpa, io, "args1.bat", args, env);
try testExecBat(gpa, io, "args2.bat", args, env);
try testExecBat(gpa, io, "args3.bat", args, env);
}
fn testExecBat(gpa: std.mem.Allocator, bat: []const u8, args: []const []const u8, env: ?*std.process.EnvMap) !void {
fn testExecBat(gpa: Allocator, io: Io, bat: []const u8, args: []const []const u8, env: ?*std.process.EnvMap) !void {
const argv = try gpa.alloc([]const u8, 1 + args.len);
defer gpa.free(argv);
argv[0] = bat;
@@ -92,8 +94,7 @@ fn testExecBat(gpa: std.mem.Allocator, bat: []const u8, args: []const []const u8
const can_have_trailing_empty_args = std.mem.eql(u8, bat, "args3.bat");
const result = try std.process.Child.run(.{
.allocator = gpa,
const result = try std.process.Child.run(gpa, io, .{
.env_map = env,
.argv = argv,
});
+6 -5
View File
@@ -1,4 +1,6 @@
const std = @import("std");
const Io = std.Io;
const Allocator = std.mem.Allocator;
pub fn main() anyerror!void {
var debug_alloc_inst: std.heap.DebugAllocator(.{}) = .init;
@@ -121,17 +123,17 @@ pub fn main() anyerror!void {
try std.testing.expectError(error.FileNotFound, tmp.dir.access("file.txt", .{}));
}
fn testExecError(err: anyerror, gpa: std.mem.Allocator, args: []const []const u8) !void {
fn testExecError(err: anyerror, gpa: Allocator, args: []const []const u8) !void {
return std.testing.expectError(err, testExec(gpa, args, null));
}
fn testExec(gpa: std.mem.Allocator, args: []const []const u8, env: ?*std.process.EnvMap) !void {
fn testExec(gpa: Allocator, args: []const []const u8, env: ?*std.process.EnvMap) !void {
try testExecBat(gpa, "args1.bat", args, env);
try testExecBat(gpa, "args2.bat", args, env);
try testExecBat(gpa, "args3.bat", args, env);
}
fn testExecBat(gpa: std.mem.Allocator, bat: []const u8, args: []const []const u8, env: ?*std.process.EnvMap) !void {
fn testExecBat(gpa: Allocator, io: Io, bat: []const u8, args: []const []const u8, env: ?*std.process.EnvMap) !void {
const argv = try gpa.alloc([]const u8, 1 + args.len);
defer gpa.free(argv);
argv[0] = bat;
@@ -139,8 +141,7 @@ fn testExecBat(gpa: std.mem.Allocator, bat: []const u8, args: []const []const u8
const can_have_trailing_empty_args = std.mem.eql(u8, bat, "args3.bat");
const result = try std.process.Child.run(.{
.allocator = gpa,
const result = try std.process.Child.run(gpa, io, .{
.env_map = env,
.argv = argv,
});
+26 -22
View File
@@ -1,4 +1,5 @@
const std = @import("std");
const Io = std.Io;
pub fn main() anyerror!void {
var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator);
@@ -9,6 +10,9 @@ pub fn main() anyerror!void {
if (args.len < 2) return error.MissingArgs;
var threaded: Io.Threaded = .init_single_threaded;
const io = threaded.io();
const exe_path = args[1];
const cwd_path = try std.process.getCwdAlloc(arena);
@@ -33,39 +37,39 @@ pub fn main() anyerror!void {
// With the special =X: environment variable set, drive-relative paths that
// don't match the CWD's drive letter are resolved against that env var.
try checkRelative(arena, "..\\..\\bar", &.{ exe_path, drive_rel, drive_abs }, null, &alt_drive_env_map);
try checkRelative(arena, "..\\baz\\foo", &.{ exe_path, drive_abs, drive_rel }, null, &alt_drive_env_map);
try checkRelative(arena, io, "..\\..\\bar", &.{ exe_path, drive_rel, drive_abs }, null, &alt_drive_env_map);
try checkRelative(arena, io, "..\\baz\\foo", &.{ exe_path, drive_abs, drive_rel }, null, &alt_drive_env_map);
// Without that environment variable set, drive-relative paths that don't match the
// CWD's drive letter are resolved against the root of the drive.
try checkRelative(arena, "..\\bar", &.{ exe_path, drive_rel, drive_abs }, null, &empty_env);
try checkRelative(arena, "..\\foo", &.{ exe_path, drive_abs, drive_rel }, null, &empty_env);
try checkRelative(arena, io, "..\\bar", &.{ exe_path, drive_rel, drive_abs }, null, &empty_env);
try checkRelative(arena, io, "..\\foo", &.{ exe_path, drive_abs, drive_rel }, null, &empty_env);
// Bare drive-relative path with no components
try checkRelative(arena, "bar", &.{ exe_path, drive_rel[0..2], drive_abs }, null, &empty_env);
try checkRelative(arena, "..", &.{ exe_path, drive_abs, drive_rel[0..2] }, null, &empty_env);
try checkRelative(arena, io, "bar", &.{ exe_path, drive_rel[0..2], drive_abs }, null, &empty_env);
try checkRelative(arena, io, "..", &.{ exe_path, drive_abs, drive_rel[0..2] }, null, &empty_env);
// Bare drive-relative path with no components, drive-CWD set
try checkRelative(arena, "..\\bar", &.{ exe_path, drive_rel[0..2], drive_abs }, null, &alt_drive_env_map);
try checkRelative(arena, "..\\baz", &.{ exe_path, drive_abs, drive_rel[0..2] }, null, &alt_drive_env_map);
try checkRelative(arena, io, "..\\bar", &.{ exe_path, drive_rel[0..2], drive_abs }, null, &alt_drive_env_map);
try checkRelative(arena, io, "..\\baz", &.{ exe_path, drive_abs, drive_rel[0..2] }, null, &alt_drive_env_map);
// Bare drive-relative path relative to the CWD should be equivalent if drive-CWD is set
try checkRelative(arena, "", &.{ exe_path, alt_drive_cwd, drive_rel[0..2] }, null, &alt_drive_env_map);
try checkRelative(arena, "", &.{ exe_path, drive_rel[0..2], alt_drive_cwd }, null, &alt_drive_env_map);
try checkRelative(arena, io, "", &.{ exe_path, alt_drive_cwd, drive_rel[0..2] }, null, &alt_drive_env_map);
try checkRelative(arena, io, "", &.{ exe_path, drive_rel[0..2], alt_drive_cwd }, null, &alt_drive_env_map);
// Bare drive-relative should always be equivalent to itself
try checkRelative(arena, "", &.{ exe_path, drive_rel[0..2], drive_rel[0..2] }, null, &alt_drive_env_map);
try checkRelative(arena, "", &.{ exe_path, drive_rel[0..2], drive_rel[0..2] }, null, &alt_drive_env_map);
try checkRelative(arena, "", &.{ exe_path, drive_rel[0..2], drive_rel[0..2] }, null, &empty_env);
try checkRelative(arena, "", &.{ exe_path, drive_rel[0..2], drive_rel[0..2] }, null, &empty_env);
try checkRelative(arena, io, "", &.{ exe_path, drive_rel[0..2], drive_rel[0..2] }, null, &alt_drive_env_map);
try checkRelative(arena, io, "", &.{ exe_path, drive_rel[0..2], drive_rel[0..2] }, null, &alt_drive_env_map);
try checkRelative(arena, io, "", &.{ exe_path, drive_rel[0..2], drive_rel[0..2] }, null, &empty_env);
try checkRelative(arena, io, "", &.{ exe_path, drive_rel[0..2], drive_rel[0..2] }, null, &empty_env);
}
if (parsed_cwd_path.kind == .unc_absolute) {
const drive_abs_path = try std.fmt.allocPrint(arena, "{c}:\\foo\\bar", .{alt_drive_letter});
{
try checkRelative(arena, drive_abs_path, &.{ exe_path, cwd_path, drive_abs_path }, null, &empty_env);
try checkRelative(arena, cwd_path, &.{ exe_path, drive_abs_path, cwd_path }, null, &empty_env);
try checkRelative(arena, io, drive_abs_path, &.{ exe_path, cwd_path, drive_abs_path }, null, &empty_env);
try checkRelative(arena, io, cwd_path, &.{ exe_path, drive_abs_path, cwd_path }, null, &empty_env);
}
} else if (parsed_cwd_path.kind == .drive_absolute) {
const cur_drive_letter = parsed_cwd_path.root[0];
@@ -73,14 +77,14 @@ pub fn main() anyerror!void {
const unc_cwd = try std.fmt.allocPrint(arena, "\\\\127.0.0.1\\{c}$\\{s}", .{ cur_drive_letter, path_beyond_root });
{
try checkRelative(arena, cwd_path, &.{ exe_path, unc_cwd, cwd_path }, null, &empty_env);
try checkRelative(arena, unc_cwd, &.{ exe_path, cwd_path, unc_cwd }, null, &empty_env);
try checkRelative(arena, io, cwd_path, &.{ exe_path, unc_cwd, cwd_path }, null, &empty_env);
try checkRelative(arena, io, unc_cwd, &.{ exe_path, cwd_path, unc_cwd }, null, &empty_env);
}
{
const drive_abs = cwd_path;
const drive_rel = parsed_cwd_path.root[0..2];
try checkRelative(arena, "", &.{ exe_path, drive_abs, drive_rel }, null, &empty_env);
try checkRelative(arena, "", &.{ exe_path, drive_rel, drive_abs }, null, &empty_env);
try checkRelative(arena, io, "", &.{ exe_path, drive_abs, drive_rel }, null, &empty_env);
try checkRelative(arena, io, "", &.{ exe_path, drive_rel, drive_abs }, null, &empty_env);
}
} else {
return error.UnexpectedPathType;
@@ -89,13 +93,13 @@ pub fn main() anyerror!void {
fn checkRelative(
allocator: std.mem.Allocator,
io: Io,
expected_stdout: []const u8,
argv: []const []const u8,
cwd: ?[]const u8,
env_map: ?*const std.process.EnvMap,
) !void {
const result = try std.process.Child.run(.{
.allocator = allocator,
const result = try std.process.Child.run(allocator, io, .{
.argv = argv,
.cwd = cwd,
.env_map = env_map,