ww build: name current directory output
This commit is contained in:
@@ -14074,6 +14074,227 @@ fn runtimepath(relative: str) str = {
|
||||
clean(root);
|
||||
};
|
||||
|
||||
// Empty build patterns select the current directory. A literal dot is
|
||||
// loading syntax, not the caller-visible output name: command publication and
|
||||
// cold scratch use the selected directory leaf without making that physical
|
||||
// leaf package or import identity.
|
||||
@test fn current_directory_build_default_output() void = {
|
||||
let root: str = fresh();
|
||||
let command: str = strings.concat(root, "/current-command");
|
||||
let library: str = strings.concat(root, "/current-library");
|
||||
let bad: str = strings.concat(root, "/bad-current");
|
||||
mkdirall(command); mkdirall(library); mkdirall(bad);
|
||||
let commandfile: str = strings.concat(command, "/main.ww");
|
||||
let original: str = "package main;\nfn main() i32 = { return 23; };\n";
|
||||
let changed: str = "package main;\nfn main() i32 = { return 24; };\n";
|
||||
writefile(commandfile, original);
|
||||
writefile(strings.concat(library, "/library.ww"), strings.concat(
|
||||
"package declared_library;\n",
|
||||
"export fn value() i32 = { return 7; };\n"));
|
||||
writefile(strings.concat(bad, "/main.ww"), strings.concat(
|
||||
"package main;\nimport missing.current;\n",
|
||||
"fn main() i32 = { return missing.current.value(); };\n"));
|
||||
|
||||
let compilerwrapper: str = strings.concat(root, "/current-w6c.sh");
|
||||
writeexecutable(compilerwrapper, strings.concat(
|
||||
"#!/bin/sh\nprintf 'compile\\n' >> \"$WW_CURRENT_TRACE\"\n",
|
||||
"if test \"$WW_CURRENT_FAIL\" = 1; then\n",
|
||||
" printf 'injected current-directory compiler failure\\n' >&2\n",
|
||||
" exit 97\nfi\nexec \"$WW_CURRENT_REAL_C\" \"$@\"\n"));
|
||||
|
||||
let stages: []str = ["ww", "ww_ww"];
|
||||
let compilers: []str = ["w6c", "w6c_ww"];
|
||||
let tags: []str = ["c", "ww"];
|
||||
let spellings: []str = ["", ".", "./"];
|
||||
let spellingtags: []str = ["bare", "dot", "slash"];
|
||||
let baseenv: []str = os.getenvs();
|
||||
let commandref: str = "";
|
||||
let changedref: str = "";
|
||||
let missingref: str = "";
|
||||
let failref: str = "";
|
||||
let collisionref: str = "";
|
||||
let out: commandout;
|
||||
let si: i32 = 0;
|
||||
for (si < stages.len) {
|
||||
rewritefile(commandfile, original);
|
||||
let defaultbin: str = strings.concat(command, "/current-command");
|
||||
let defaultscratch: str = strings.concat(defaultbin, ".sepwork");
|
||||
let legacyscratch: str = strings.concat(command, "/..sepwork");
|
||||
|
||||
// Bare, dot, and dot-slash spellings select the same package and
|
||||
// produce the same directory-named executable and cold artifacts.
|
||||
let pi: i32 = 0;
|
||||
for (pi < spellings.len) {
|
||||
let av: []str = [driver(stages[si]), "build"];
|
||||
if (spellings[pi].len != 0) { append(av, spellings[pi]); };
|
||||
runcommanddir(root, strings.concat("current-", tags[si], "-",
|
||||
spellingtags[pi]), command, av,
|
||||
(60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0);
|
||||
assert(os.exists(defaultbin) && os.exists(defaultscratch));
|
||||
assert(!os.exists(legacyscratch));
|
||||
assert((permissionmode(defaultbin) & 73u32) == 73u32);
|
||||
let built: str = readfile(defaultbin);
|
||||
if (commandref.len == 0) { commandref = strings.dup(built); }
|
||||
else { assert(same(commandref, built)); };
|
||||
let runav: []str = [defaultbin];
|
||||
runcommand(root, strings.concat("current-run-", tags[si], "-",
|
||||
spellingtags[pi]), runav, time.second, &out);
|
||||
expectexit(&out, 23);
|
||||
assert(!directoryhasnew(command)
|
||||
&& !directoryhasfragment(command, ".install")
|
||||
&& !directoryhasfragment(command, ".wwtxn."));
|
||||
assert(os.remove(defaultbin) == 0);
|
||||
clean(defaultscratch);
|
||||
pi += 1;
|
||||
};
|
||||
|
||||
// Explicit output and exact null output keep their established
|
||||
// disposition and never create the default current-directory name.
|
||||
let explicitout: str = strings.concat(root, "/explicit-", tags[si]);
|
||||
let explicitav: []str = [driver(stages[si]), "build", "-o",
|
||||
explicitout];
|
||||
runcommanddir(root, strings.concat("current-explicit-", tags[si]),
|
||||
command, explicitav,
|
||||
(60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0);
|
||||
assert(same(commandref, readfile(explicitout))
|
||||
&& !os.exists(defaultbin) && !os.exists(defaultscratch));
|
||||
assert(os.remove(explicitout) == 0);
|
||||
clean(strings.concat(explicitout, ".sepwork"));
|
||||
let nullav: []str = [driver(stages[si]), "build", "-o", "/dev/null"];
|
||||
runcommanddir(root, strings.concat("current-null-", tags[si]), command,
|
||||
nullav, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0);
|
||||
assert(!os.exists(defaultbin) && !os.exists(defaultscratch)
|
||||
&& !os.exists(legacyscratch));
|
||||
|
||||
// A non-main current-directory build compiles and archives privately,
|
||||
// but neither links nor publishes a directory-named file.
|
||||
let librarybin: str = strings.concat(library, "/current-library");
|
||||
let libraryscratch: str = strings.concat(librarybin, ".sepwork");
|
||||
let librarylegacy: str = strings.concat(library, "/..sepwork");
|
||||
let libraryav: []str = [driver(stages[si]), "build"];
|
||||
runcommanddir(root, strings.concat("current-library-", tags[si]),
|
||||
library, libraryav,
|
||||
(60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0);
|
||||
assert(!os.exists(librarybin) && os.exists(libraryscratch)
|
||||
&& !os.exists(librarylegacy));
|
||||
assert(!directoryhasnew(library)
|
||||
&& !directoryhasfragment(library, ".wwtxn."));
|
||||
clean(libraryscratch);
|
||||
|
||||
// Import loading retains precedence over output planning. Failure
|
||||
// creates neither the corrected output nor either scratch spelling.
|
||||
let badbin: str = strings.concat(bad, "/bad-current");
|
||||
let badav: []str = [driver(stages[si]), "build"];
|
||||
runcommanddir(root, strings.concat("current-missing-", tags[si]), bad,
|
||||
badav, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(out.stdout.len == 0
|
||||
&& has(out.stderr, "cannot find package missing.current\n"));
|
||||
assert(!os.exists(badbin)
|
||||
&& !os.exists(strings.concat(badbin, ".sepwork"))
|
||||
&& !os.exists(strings.concat(bad, "/..sepwork")));
|
||||
if (si == 0) { missingref = strings.dup(out.stderr); }
|
||||
else { assert(same(missingref, out.stderr)); };
|
||||
|
||||
// Persistent cold/warm reuse keeps the same output. An invalidated
|
||||
// producer failure preserves both that prior output and clean public
|
||||
// state; a later successful invalidation publishes the changed binary.
|
||||
let work: str = strings.concat(root, "/current-work-", tags[si]);
|
||||
let trace: str = strings.concat(root, "/current-trace-", tags[si]);
|
||||
mkdirall(work); writefile(trace, "");
|
||||
let env: []str = alloc([], (baseenv.len + 4): u64)!;
|
||||
let ei: i32 = 0;
|
||||
for (ei < baseenv.len) {
|
||||
if (!strings.hasprefix(baseenv[ei], "WW_W6C=")
|
||||
&& !strings.hasprefix(baseenv[ei], "WW_CURRENT_")) {
|
||||
append(env, baseenv[ei]);
|
||||
};
|
||||
ei += 1;
|
||||
};
|
||||
append(env, strings.concat("WW_W6C=", compilerwrapper));
|
||||
append(env, strings.concat("WW_CURRENT_REAL_C=",
|
||||
driver(compilers[si])));
|
||||
append(env, strings.concat("WW_CURRENT_TRACE=", trace));
|
||||
let failindex: i32 = env.len;
|
||||
append(env, "WW_CURRENT_FAIL=");
|
||||
let persistav: []str = [driver(stages[si]), "build", "-w", work];
|
||||
runcommandenvdir(root, strings.concat("current-cold-", tags[si]),
|
||||
persistav, env, command,
|
||||
(60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0
|
||||
&& readfile(trace).len != 0);
|
||||
let prior: str = readfile(defaultbin);
|
||||
assert(same(commandref, prior));
|
||||
rewritefile(trace, "");
|
||||
runcommandenvdir(root, strings.concat("current-warm-", tags[si]),
|
||||
persistav, env, command,
|
||||
(60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0
|
||||
&& readfile(trace).len == 0 && same(prior, readfile(defaultbin)));
|
||||
rewritefile(commandfile, changed); rewritefile(trace, "");
|
||||
env[failindex] = "WW_CURRENT_FAIL=1";
|
||||
runcommandenvdir(root, strings.concat("current-fail-", tags[si]),
|
||||
persistav, env, command,
|
||||
(60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(readfile(trace).len != 0
|
||||
&& has(out.stderr, "injected current-directory compiler failure\n")
|
||||
&& has(out.stderr, "ww: w6c failed for ")
|
||||
&& same(prior, readfile(defaultbin)));
|
||||
assert(!directoryhasnew(command) && !directoryhasnew(work)
|
||||
&& !directoryhasfragment(command, ".install")
|
||||
&& !directoryhasfragment(command, ".wwtxn.")
|
||||
&& !directoryhasfragment(work, ".wwtxn."));
|
||||
if (si == 0) { failref = strings.dup(out.stderr); }
|
||||
else { assert(same(failref, out.stderr)); };
|
||||
env[failindex] = "WW_CURRENT_FAIL="; rewritefile(trace, "");
|
||||
runcommandenvdir(root, strings.concat("current-changed-", tags[si]),
|
||||
persistav, env, command,
|
||||
(60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0
|
||||
&& readfile(trace).len != 0);
|
||||
let changedbytes: str = readfile(defaultbin);
|
||||
assert(!same(prior, changedbytes));
|
||||
if (changedref.len == 0) { changedref = strings.dup(changedbytes); }
|
||||
else { assert(same(changedref, changedbytes)); };
|
||||
let changedrun: []str = [defaultbin];
|
||||
runcommand(root, strings.concat("current-changed-run-", tags[si]),
|
||||
changedrun, time.second, &out);
|
||||
expectexit(&out, 24);
|
||||
assert(os.remove(defaultbin) == 0);
|
||||
clean(work);
|
||||
rewritefile(commandfile, original);
|
||||
|
||||
// A genuine destination-directory collision still rejects at output
|
||||
// preflight, now naming the derived leaf rather than the dot selector.
|
||||
mkdirall(defaultbin);
|
||||
runcommanddir(root, strings.concat("current-collision-", tags[si]),
|
||||
command, libraryav,
|
||||
(60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(out.stdout.len == 0 && same(out.stderr, strings.concat(
|
||||
"ww: build output \"current-command\" already exists and is a directory\n")));
|
||||
assert(!os.exists(defaultscratch) && !os.exists(legacyscratch));
|
||||
if (si == 0) { collisionref = strings.dup(out.stderr); }
|
||||
else { assert(same(collisionref, out.stderr)); };
|
||||
clean(defaultbin);
|
||||
si += 1;
|
||||
};
|
||||
assert(!directoryhasnew(root) && !directoryhasfragment(root, ".wwtxn."));
|
||||
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