ww: put selected toolchain first in test PATH

This commit is contained in:
2026-08-21 05:30:10 +09:00
parent 1b71250ad5
commit 9b6b1100f4
7 changed files with 586 additions and 96 deletions

View File

@@ -1632,6 +1632,88 @@ fn sepallocptrs(cap: i32) ([]*u8 | nomem) = {
return value;
};
type septestenv = struct {
values: []str,
path: str,
};
// Pinned cmd/go gives each test binary PATH=$GOROOT/bin:$PATH. The selected
// WW driver's sibling directory is the local toolchain-bin analogue. Remove
// normal inherited PATH duplicates because lib/os/exec deliberately preserves
// the concrete environment array while Go's os/exec keeps the appended value.
fn sepmaketestenv(toolbin: str, out: *septestenv) bool = {
let inherited: []str = os.getenvs();
if (inherited.len == SEP_COUNT_MAX) {
cerr("ww: cannot prepare test environment\n");
return false;
};
let oldpath: str = "";
match (os.getenv("PATH")) {
case let value: str => oldpath = value;
case void => void;
};
let total: i64 = 5i64 + (toolbin.len: i64);
if (oldpath.len != 0) { total += 1i64 + (oldpath.len: i64); };
if (total > SEP_COUNT_MAX: i64) {
cerr("ww: cannot prepare test environment\n");
return false;
};
let pathallocation: ([]u8 | nomem) = sepallocbytes(total: i32);
let pathbytes: []u8;
match (pathallocation) {
case let value: []u8 => pathbytes = value;
case nomem => {
cerr("ww: cannot prepare test environment\n");
return false;
};
};
let prefix: str = "PATH=";
let i: i32 = 0;
for (i < prefix.len) { append(pathbytes, prefix[i]); i += 1; };
i = 0;
for (i < toolbin.len) { append(pathbytes, toolbin[i]); i += 1; };
if (oldpath.len != 0) {
append(pathbytes, ':');
i = 0;
for (i < oldpath.len) { append(pathbytes, oldpath[i]); i += 1; };
};
let pathenv: str = strings.frombytes(pathbytes);
let envallocation: ([]str | nomem) = sepallocstrs(inherited.len + 1);
let env: []str;
match (envallocation) {
case let value: []str => env = value;
case nomem => {
os.free(pathenv.ptr: *void, pathenv.len: u64);
cerr("ww: cannot prepare test environment\n");
return false;
};
};
i = 0;
let inserted: bool = false;
for (i < inherited.len) {
if (strings.hasprefix(inherited[i], "PATH=")) {
if (!inserted) { append(env, pathenv); inserted = true; };
} else {
append(env, inherited[i]);
};
i += 1;
};
if (!inserted) { append(env, pathenv); };
out.values = env;
out.path = pathenv;
return true;
};
fn sepfreetestenv(env: *septestenv) void = {
if (env.path.ptr != nil && env.path.len != 0) {
os.free(env.path.ptr: *void, env.path.len: u64);
};
if (env.values.ptr != nil && env.values.cap != 0) {
os.free(env.values.ptr: *void,
(env.values.cap: u64) * (size(str): u64));
};
};
fn sepallocgraph(pkg: []seppkg, context: []sepcontext) (*sepgraph | nomem) = {
let emptyfolds: []sepfoldentry;
let value: *sepgraph = alloc(sepgraph{
@@ -9186,21 +9268,30 @@ fn runsingletest(selfdir: *u8, src: *u8, incs: *u8, compileonly: i32,
if (pattern != nil) {
append(execargv, pathstr(pattern));
};
let env: []str = os.getenvs();
let result: exec.result;
exec.runstdio(pathstr(outp), execargv, env, &result);
let rc: i32 = 1;
if (result.termination == exec.termination.EXIT) {
rc = result.code;
} else { if (result.termination == exec.termination.ERROR) {
if (result.code == 127) {
cerr("ww: execve failed\n");
rc = 127;
} else {
cerr("ww: process launch/wait failed\n");
rc = -1;
};
let env: septestenv;
let toolbin: *u8 = canonicaldir(pathstr(selfdir));
if (toolbin == nil) {
cerr("ww: cannot prepare test environment\n");
} else { if (sepmaketestenv(pathstr(toolbin), &env)) {
exec.runstdio(pathstr(outp), execargv, env.values, &result);
sepfreetestenv(&env);
if (result.termination == exec.termination.EXIT) {
rc = result.code;
} else { if (result.termination == exec.termination.ERROR) {
if (result.code == 127) {
cerr("ww: execve failed\n");
rc = 127;
} else {
cerr("ww: process launch/wait failed\n");
rc = -1;
};
}; };
}; };
if (toolbin != nil) {
os.free(toolbin: *void, cstrlen(toolbin) + 1u64);
};
if (rc == 0 && deferredinstall
&& sepinstalltestoutput(outp, outstem) != 0) { rc = 1; };
if (owntmp) {