ww: protect public install outputs
This commit is contained in:
@@ -12443,7 +12443,6 @@ fn runtimepath(relative: str) str = {
|
||||
let rollbackdiag: str = "";
|
||||
let missingdiag: str = "";
|
||||
let occupieddiag: str = "";
|
||||
let failurebytes: str = "";
|
||||
let persistbasebytes: str = "";
|
||||
let persistchangedbytes: str = "";
|
||||
let baseenv: []str = os.getenvs();
|
||||
@@ -12595,29 +12594,23 @@ fn runtimepath(relative: str) str = {
|
||||
" [no tests]\n")));
|
||||
assert(out.stderr.len == 0 && !os.exists(noneroot));
|
||||
|
||||
// Publication commits before execution. A failing test therefore leaves
|
||||
// a runnable retained binary while its product failure stays on stdout.
|
||||
// Pinned builderTest makes the install action depend on the run action.
|
||||
// A failing run therefore preserves a prior destination and never enters
|
||||
// the retained-output overwrite guard.
|
||||
let failurebin: str = strings.concat(root, "/failure-", tags[si],
|
||||
".test");
|
||||
writefile(failurebin, "failure-sentinel\n");
|
||||
let failureav: []str = [driver(stages[si]), "test", "-I", suite,
|
||||
"-o", failurebin, failed];
|
||||
runcommandenvdir(root, strings.concat("publish-runtime-", tags[si]),
|
||||
failureav, env, root,
|
||||
(60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(os.exists(failurebin) && !os.exists(strings.concat(failurebin,
|
||||
".new")));
|
||||
assert(same(readfile(failurebin), "failure-sentinel\n"));
|
||||
assert(!os.exists(strings.concat(failurebin, ".new")));
|
||||
assert(has(out.stdout,
|
||||
"failed_decl.runtime_failure ... FAIL (exit 1)\n"));
|
||||
assert(out.stderr.len == 0);
|
||||
let fi: os.filestat;
|
||||
match (os.stat(&fi, failurebin)) {
|
||||
case void => void;
|
||||
case let e: os.oserror => abort("retained failure binary missing");
|
||||
};
|
||||
assert(((fi.mode: u32) & 73u32) != 0u32);
|
||||
if (si == 0) { failurebytes = readfile(failurebin); }
|
||||
else { assert(same(failurebytes, readfile(failurebin))); };
|
||||
|
||||
// -w keeps semantic actions persistent while -c and -o remain execution
|
||||
// and presentation policy. Compile-only can cold-build and invalidate;
|
||||
@@ -12681,6 +12674,377 @@ fn runtimepath(relative: str) str = {
|
||||
clean(root);
|
||||
};
|
||||
|
||||
// Go 1.26.5's BuildInstallFunc protects caller data at the install boundary:
|
||||
// after producers, and after a successful run for retained running tests.
|
||||
// Exercise that one predicate through direct, raw, package, and test routes.
|
||||
@test fn public_output_overwrite_safety() void = {
|
||||
let root: str = fresh();
|
||||
let source: str = strings.concat(root, "/source");
|
||||
let dep: str = strings.concat(source, "/lib/dep");
|
||||
let app: str = strings.concat(source, "/cmd/app");
|
||||
let bad: str = strings.concat(source, "/cmd/bad");
|
||||
let checked: str = strings.concat(source, "/pkg/check");
|
||||
let failed: str = strings.concat(source, "/pkg/failed");
|
||||
let invocation: str = strings.concat(root, "/invoke");
|
||||
mkdirall(dep); mkdirall(app); mkdirall(bad); mkdirall(checked);
|
||||
mkdirall(failed); mkdirall(invocation);
|
||||
writefile(strings.concat(dep, "/dep.ww"), strings.concat(
|
||||
"package renamed;\n",
|
||||
"export fn value() int = { return 9; };\n"));
|
||||
let appsource: str = strings.concat(app, "/main.ww");
|
||||
let appbase: str = strings.concat(
|
||||
"package main;\n",
|
||||
"import stable lib.dep;\n",
|
||||
"export fn main() int = { return stable.value(); };\n");
|
||||
let appchanged: str = strings.concat(
|
||||
"package main;\n",
|
||||
"import stable lib.dep;\n",
|
||||
"export fn main() int = { return stable.value() + 1; };\n");
|
||||
writefile(appsource, appbase);
|
||||
writefile(strings.concat(bad, "/main.ww"), strings.concat(
|
||||
"package main;\n",
|
||||
"import missing nowhere.present;\n",
|
||||
"export fn main() int = { return missing.value(); };\n"));
|
||||
writefile(strings.concat(checked, "/check.ww"),
|
||||
"package checked;\nfn value() int = { return 4; };\n");
|
||||
writefile(strings.concat(checked, "/check_test.ww"), strings.concat(
|
||||
"package checked;\n",
|
||||
"@test fn guarded_run() void = { assert(value() == 4); };\n"));
|
||||
writefile(strings.concat(failed, "/failed_test.ww"), strings.concat(
|
||||
"package failed;\n",
|
||||
"@test fn failed_run() void = { assert(false); };\n"));
|
||||
let raw: str = strings.concat(root, "/raw.ww");
|
||||
writefile(raw,
|
||||
"package main;\nexport fn main() int = { return 3; };\n");
|
||||
|
||||
let linkerwrapper: str = strings.concat(root, "/overwrite-w6l.sh");
|
||||
writeexecutable(linkerwrapper, strings.concat(
|
||||
"#!/bin/sh\n",
|
||||
"printf 'link\\n' >> \"$WW_OVERWRITE_TRACE\"\n",
|
||||
"exec \"$WW_OVERWRITE_REAL_L\" \"$@\"\n"));
|
||||
let drivers: []str = ["ww", "ww_ww"];
|
||||
let linkers: []str = ["w6l", "w6l_ww"];
|
||||
let tags: []str = ["c", "ww"];
|
||||
let commandout: str = strings.concat(root, "/command.bin");
|
||||
let rawout: str = strings.concat(root, "/raw.bin");
|
||||
let defaultout: str = strings.concat(invocation, "/app");
|
||||
let libout: str = strings.concat(root, "/library.a");
|
||||
let testbin: str = strings.concat(root, "/check.test");
|
||||
let symlinktarget: str = strings.concat(root, "/symlink-target");
|
||||
let symlinkout: str = strings.concat(root, "/symlink.bin");
|
||||
let fifoout: str = strings.concat(root, "/fifo.bin");
|
||||
writefile(symlinktarget, "symlink-sentinel\n");
|
||||
assert(os.symlink(symlinktarget, symlinkout) == 0);
|
||||
let builddir: str = strings.concat(root, "/build-output");
|
||||
let buildchild: str = strings.concat(builddir, "/app");
|
||||
let testdir: str = strings.concat(root, "/test-output");
|
||||
let testchild: str = strings.concat(testdir, "/check.test");
|
||||
mkdirall(buildchild); mkdirall(testchild);
|
||||
writefile(strings.concat(buildchild, "/marker"), "build-directory\n");
|
||||
writefile(strings.concat(testchild, "/marker"), "test-directory\n");
|
||||
|
||||
let commanddiag: str = "";
|
||||
let rawdiag: str = "";
|
||||
let defaultdiag: str = "";
|
||||
let symlinkdiag: str = "";
|
||||
let builddirdiag: str = "";
|
||||
let librarydiag: str = "";
|
||||
let libraryarchivediag: str = "";
|
||||
let testcompilediag: str = "";
|
||||
let testrundiag: str = "";
|
||||
let testdirdiag: str = "";
|
||||
let loaddiag: str = "";
|
||||
let commandbytes: str = "";
|
||||
let librarybytes: str = "";
|
||||
let interfacebytes: str = "";
|
||||
let testbytes: str = "";
|
||||
let unitbytes: str = "";
|
||||
let baseenv: []str = os.getenvs();
|
||||
let out: commandout;
|
||||
let si: i32 = 0;
|
||||
for (si < drivers.len) {
|
||||
let trace: str = strings.concat(root, "/overwrite-", tags[si],
|
||||
".trace");
|
||||
writefile(trace, "");
|
||||
let env: []str = alloc([], (baseenv.len + 3): u64)!;
|
||||
let ei: i32 = 0;
|
||||
for (ei < baseenv.len) {
|
||||
if (!strings.hasprefix(baseenv[ei], "WW_W6L=")
|
||||
&& !strings.hasprefix(baseenv[ei], "WW_OVERWRITE_TRACE=")
|
||||
&& !strings.hasprefix(baseenv[ei], "WW_OVERWRITE_REAL_L=")) {
|
||||
append(env, baseenv[ei]);
|
||||
};
|
||||
ei += 1;
|
||||
};
|
||||
append(env, strings.concat("WW_W6L=", linkerwrapper));
|
||||
append(env, strings.concat("WW_OVERWRITE_TRACE=", trace));
|
||||
append(env, strings.concat("WW_OVERWRITE_REAL_L=",
|
||||
driver(linkers[si])));
|
||||
let work: str = strings.concat(root, "/command-work-", tags[si]);
|
||||
let badwork: str = strings.concat(root, "/bad-work-", tags[si]);
|
||||
let rawwork: str = strings.concat(root, "/raw-work-", tags[si]);
|
||||
let defaultwork: str = strings.concat(root, "/default-work-", tags[si]);
|
||||
let symlinkwork: str = strings.concat(root, "/symlink-work-", tags[si]);
|
||||
let fifowork: str = strings.concat(root, "/fifo-work-", tags[si]);
|
||||
let dirwork: str = strings.concat(root, "/dir-work-", tags[si]);
|
||||
let libwork: str = strings.concat(root, "/lib-work-", tags[si]);
|
||||
let testwork: str = strings.concat(root, "/test-work-", tags[si]);
|
||||
let testdirwork: str = strings.concat(root, "/test-dir-work-", tags[si]);
|
||||
mkdirall(work); mkdirall(badwork); mkdirall(rawwork);
|
||||
mkdirall(defaultwork); mkdirall(symlinkwork); mkdirall(fifowork);
|
||||
mkdirall(dirwork);
|
||||
mkdirall(libwork); mkdirall(testwork); mkdirall(testdirwork);
|
||||
|
||||
// A nonempty caller file rejects only after the linker ran, and a cold
|
||||
// persistent generation remains unpublished.
|
||||
if (os.exists(commandout)) { assert(os.remove(commandout) == 0); };
|
||||
writefile(commandout, "caller-command\n");
|
||||
rewritefile(trace, "");
|
||||
let commandav: []str = [driver(drivers[si]), "build", "-w", work,
|
||||
"-I", source, "-o", commandout, "cmd.app"];
|
||||
runcommandenv(root, strings.concat("overwrite-command-", tags[si]),
|
||||
commandav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(has(out.stderr, strings.concat("ww: build output \"", commandout,
|
||||
"\" already exists and is not an object file\n")));
|
||||
assert(same(readfile(commandout), "caller-command\n"));
|
||||
assert(permissionmode(commandout) == 384u32);
|
||||
assert(readfile(trace).len != 0 && directoryisempty(work));
|
||||
assert(!os.exists(strings.concat(commandout, ".new"))
|
||||
&& !directoryhasfragment(root, "command.bin.wwtxn."));
|
||||
if (si == 0) { commanddiag = strings.dup(out.stderr); }
|
||||
else { assert(same(commanddiag, out.stderr)); };
|
||||
|
||||
// Package/import failure keeps load precedence and starts no linker.
|
||||
rewritefile(trace, "");
|
||||
let badav: []str = [driver(drivers[si]), "build", "-w", badwork,
|
||||
"-I", source, "-o", commandout, "cmd.bad"];
|
||||
runcommandenv(root, strings.concat("overwrite-load-", tags[si]), badav,
|
||||
env, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(has(out.stderr, "cannot find package nowhere.present"));
|
||||
assert(!has(out.stderr, "already exists and is not an object file"));
|
||||
assert(readfile(trace).len == 0 && directoryisempty(badwork));
|
||||
assert(same(readfile(commandout), "caller-command\n"));
|
||||
if (si == 0) { loaddiag = strings.dup(out.stderr); }
|
||||
else { assert(same(loaddiag, out.stderr)); };
|
||||
|
||||
// Empty reservations and recognized ELF outputs are replaceable. A
|
||||
// rejected invalidation preserves the prior persistent generation.
|
||||
rewritefile(commandout, ""); rewritefile(trace, "");
|
||||
runcommandenv(root, strings.concat("overwrite-empty-", tags[si]),
|
||||
commandav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
let built: str = readfile(commandout);
|
||||
assert(strings.hasprefix(built, "\x7fELF"));
|
||||
let unit: str = readfile(strings.concat(work, "/cmd.app.unit.ww"));
|
||||
if (si == 0) {
|
||||
commandbytes = strings.dup(built);
|
||||
unitbytes = strings.dup(unit);
|
||||
} else {
|
||||
assert(same(commandbytes, built) && same(unitbytes, unit));
|
||||
};
|
||||
rewritefile(appsource, appchanged);
|
||||
rewritefile(commandout, "caller-after-change\n");
|
||||
rewritefile(trace, "");
|
||||
runcommandenv(root, strings.concat("overwrite-invalidated-", tags[si]),
|
||||
commandav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(readfile(trace).len != 0);
|
||||
assert(same(readfile(commandout), "caller-after-change\n"));
|
||||
assert(same(readfile(strings.concat(work, "/cmd.app.unit.ww")), unit));
|
||||
rewritefile(appsource, appbase);
|
||||
rewritefile(commandout, built);
|
||||
runcommandenv(root, strings.concat("overwrite-elf-", tags[si]),
|
||||
commandav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
let runav: []str = [commandout];
|
||||
runcommand(root, strings.concat("overwrite-command-run-", tags[si]),
|
||||
runav, (10i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 9);
|
||||
|
||||
// Default, raw, symlink-following, and output-directory child routes
|
||||
// use the same late guard and never strand rollback backups.
|
||||
if (os.exists(defaultout)) { rewritefile(defaultout, "default-sentinel\n"); }
|
||||
else { writefile(defaultout, "default-sentinel\n"); };
|
||||
let defaultav: []str = [driver(drivers[si]), "build", "-w",
|
||||
defaultwork, "-I", source, "cmd.app"];
|
||||
runcommandenvdir(root, strings.concat("overwrite-default-", tags[si]),
|
||||
defaultav, env, invocation,
|
||||
(60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(same(readfile(defaultout), "default-sentinel\n"));
|
||||
if (si == 0) { defaultdiag = strings.dup(out.stderr); }
|
||||
else { assert(same(defaultdiag, out.stderr)); };
|
||||
if (os.exists(rawout)) { rewritefile(rawout, "raw-sentinel\n"); }
|
||||
else { writefile(rawout, "raw-sentinel\n"); };
|
||||
let rawav: []str = [driver(drivers[si]), "build", "-w", rawwork,
|
||||
"-o", rawout, raw];
|
||||
runcommandenv(root, strings.concat("overwrite-raw-", tags[si]), rawav,
|
||||
env, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(same(readfile(rawout), "raw-sentinel\n"));
|
||||
if (si == 0) { rawdiag = strings.dup(out.stderr); }
|
||||
else { assert(same(rawdiag, out.stderr)); };
|
||||
let symlinkav: []str = [driver(drivers[si]), "build", "-w",
|
||||
symlinkwork, "-I", source, "-o", symlinkout, "cmd.app"];
|
||||
runcommandenv(root, strings.concat("overwrite-symlink-", tags[si]),
|
||||
symlinkav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(same(readfile(symlinkout), "symlink-sentinel\n"));
|
||||
if (si == 0) { symlinkdiag = strings.dup(out.stderr); }
|
||||
else { assert(same(symlinkdiag, out.stderr)); };
|
||||
if (os.exists(fifoout)) { assert(os.remove(fifoout) == 0); };
|
||||
let fifoav: []str = ["/usr/bin/mkfifo", fifoout];
|
||||
runcommand(root, strings.concat("overwrite-mkfifo-", tags[si]), fifoav,
|
||||
(10i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
let fifobuildav: []str = [driver(drivers[si]), "build", "-w",
|
||||
fifowork, "-I", source, "-o", fifoout, "cmd.app"];
|
||||
runcommandenv(root, strings.concat("overwrite-fifo-", tags[si]),
|
||||
fifobuildav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(strings.hasprefix(readfile(fifoout), "\x7fELF"));
|
||||
let dirav: []str = [driver(drivers[si]), "build", "-w", dirwork,
|
||||
"-I", source, "-o", strings.concat(builddir, "/"), "cmd.app"];
|
||||
runcommandenv(root, strings.concat("overwrite-build-dir-", tags[si]),
|
||||
dirav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(has(out.stderr, "already exists and is a directory"));
|
||||
assert(same(readfile(strings.concat(buildchild, "/marker")),
|
||||
"build-directory\n"));
|
||||
assert(!directoryhasfragment(builddir, ".wwtxn."));
|
||||
if (si == 0) { builddirdiag = strings.dup(out.stderr); }
|
||||
else { assert(same(builddirdiag, out.stderr)); };
|
||||
|
||||
// Archive and WW-interface outputs each participate in the guard. An
|
||||
// ordinary repeat accepts both recognized prior outputs; arbitrary
|
||||
// interface or archive text rejects without changing either member.
|
||||
if (os.exists(libout)) { assert(os.remove(libout) == 0); };
|
||||
if (os.exists(strings.concat(libout, ".wwi"))) {
|
||||
assert(os.remove(strings.concat(libout, ".wwi")) == 0);
|
||||
};
|
||||
let libav: []str = [driver(drivers[si]), "build", "-w", libwork,
|
||||
"-I", source, "-o", libout, "lib.dep"];
|
||||
runcommandenv(root, strings.concat("overwrite-library-new-", tags[si]),
|
||||
libav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
let archive: str = readfile(libout);
|
||||
let iface: str = readfile(strings.concat(libout, ".wwi"));
|
||||
assert(strings.hasprefix(archive, "!<arch>\n"));
|
||||
assert(strings.hasprefix(iface, "//ww:module "));
|
||||
runcommandenv(root, strings.concat("overwrite-library-repeat-", tags[si]),
|
||||
libav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(same(archive, readfile(libout))
|
||||
&& same(iface, readfile(strings.concat(libout, ".wwi"))));
|
||||
if (si == 0) {
|
||||
librarybytes = strings.dup(archive);
|
||||
interfacebytes = strings.dup(iface);
|
||||
} else {
|
||||
assert(same(librarybytes, archive)
|
||||
&& same(interfacebytes, iface));
|
||||
};
|
||||
rewritefile(strings.concat(libout, ".wwi"), "caller-interface\n");
|
||||
runcommandenv(root, strings.concat("overwrite-library-reject-", tags[si]),
|
||||
libav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(same(readfile(libout), archive));
|
||||
assert(same(readfile(strings.concat(libout, ".wwi")),
|
||||
"caller-interface\n"));
|
||||
if (si == 0) { librarydiag = strings.dup(out.stderr); }
|
||||
else { assert(same(librarydiag, out.stderr)); };
|
||||
rewritefile(libout, "caller-archive\n");
|
||||
rewritefile(strings.concat(libout, ".wwi"), iface);
|
||||
runcommandenv(root, strings.concat("overwrite-library-archive-",
|
||||
tags[si]), libav, env,
|
||||
(60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(same(readfile(libout), "caller-archive\n"));
|
||||
assert(same(readfile(strings.concat(libout, ".wwi")), iface));
|
||||
if (si == 0) { libraryarchivediag = strings.dup(out.stderr); }
|
||||
else { assert(same(libraryarchivediag, out.stderr)); };
|
||||
|
||||
// Compile-only installs check after linking. Running retention executes
|
||||
// the private test first; a successful run then checks, while a failed
|
||||
// run never installs or diagnoses the caller destination.
|
||||
if (os.exists(testbin)) { rewritefile(testbin, "caller-test\n"); }
|
||||
else { writefile(testbin, "caller-test\n"); };
|
||||
let testcompileav: []str = [driver(drivers[si]), "test", "-c", "-w",
|
||||
testwork, "-I", source, "-o", testbin, "pkg.check"];
|
||||
runcommandenv(root, strings.concat("overwrite-test-c-", tags[si]),
|
||||
testcompileav, env,
|
||||
(90i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(same(readfile(testbin), "caller-test\n"));
|
||||
if (si == 0) { testcompilediag = strings.dup(out.stderr); }
|
||||
else { assert(same(testcompilediag, out.stderr)); };
|
||||
rewritefile(testbin, "");
|
||||
runcommandenv(root, strings.concat("overwrite-test-empty-", tags[si]),
|
||||
testcompileav, env,
|
||||
(90i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
let compiledtest: str = readfile(testbin);
|
||||
assert(strings.hasprefix(compiledtest, "\x7fELF"));
|
||||
if (si == 0) { testbytes = strings.dup(compiledtest); }
|
||||
else { assert(same(testbytes, compiledtest)); };
|
||||
rewritefile(testbin, "caller-running-test\n");
|
||||
let testrunav: []str = [driver(drivers[si]), "test", "-w", testwork,
|
||||
"-I", source, "-o", testbin, "pkg.check"];
|
||||
runcommandenv(root, strings.concat("overwrite-test-run-", tags[si]),
|
||||
testrunav, env, (90i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(has(out.stdout, "checked.guarded_run ... ok\n"));
|
||||
assert(same(readfile(testbin), "caller-running-test\n"));
|
||||
if (si == 0) { testrundiag = strings.dup(out.stderr); }
|
||||
else { assert(same(testrundiag, out.stderr)); };
|
||||
rewritefile(testbin, compiledtest);
|
||||
runcommandenv(root, strings.concat("overwrite-test-elf-", tags[si]),
|
||||
testrunav, env, (90i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(has(out.stdout, "checked.guarded_run ... ok\n"));
|
||||
let beforefailure: str = readfile(testbin);
|
||||
let failav: []str = [driver(drivers[si]), "test", "-w", testwork,
|
||||
"-I", source, "-o", testbin, "pkg.failed"];
|
||||
runcommandenv(root, strings.concat("overwrite-test-fail-", tags[si]),
|
||||
failav, env, (90i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(has(out.stdout, "failed.failed_run ... FAIL (exit 1)\n"));
|
||||
assert(out.stderr.len == 0 && same(readfile(testbin), beforefailure));
|
||||
assert(!os.exists(strings.concat(testbin, ".new"))
|
||||
&& !os.exists(strings.concat(testbin, ".install")));
|
||||
let testdirav: []str = [driver(drivers[si]), "test", "-c", "-w",
|
||||
testdirwork, "-I", source, "-o", strings.concat(testdir, "/"),
|
||||
"pkg.check"];
|
||||
runcommandenv(root, strings.concat("overwrite-test-dir-", tags[si]),
|
||||
testdirav, env, (90i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(has(out.stderr, "already exists and is a directory"));
|
||||
assert(same(readfile(strings.concat(testchild, "/marker")),
|
||||
"test-directory\n"));
|
||||
assert(!directoryhasfragment(testdir, ".wwtxn."));
|
||||
if (si == 0) { testdirdiag = strings.dup(out.stderr); }
|
||||
else { assert(same(testdirdiag, out.stderr)); };
|
||||
|
||||
// Assembly and exact-null routes have no public install action.
|
||||
let asmout: str = strings.concat(root, "/assembly-", tags[si]);
|
||||
writefile(asmout, "assembly-sentinel\n");
|
||||
let asmav: []str = [driver(drivers[si]), "build", "-S", "-w",
|
||||
work, "-I", source, "-o", asmout, "cmd.app"];
|
||||
runcommandenv(root, strings.concat("overwrite-asm-", tags[si]), asmav,
|
||||
env, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(same(readfile(asmout), "assembly-sentinel\n"));
|
||||
let nullav: []str = [driver(drivers[si]), "build", "-I", source,
|
||||
"-o", "/dev/null", "cmd.app"];
|
||||
runcommandenv(root, strings.concat("overwrite-null-", tags[si]), nullav,
|
||||
env, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
si += 1;
|
||||
};
|
||||
clean(root);
|
||||
};
|
||||
|
||||
// A single directory root used to bypass the package coordinator and treat
|
||||
// every non-null -o spelling as one file. Exercise the Go output-directory
|
||||
// branch at that dispatch boundary while the established graph transaction
|
||||
|
||||
Reference in New Issue
Block a user