ww: invalidate partial package commits
This commit is contained in:
@@ -7879,6 +7879,8 @@ fn runtimepath(relative: str) str = {
|
||||
let scopetwo: str = strings.concat(source, "/scope/two");
|
||||
let scoped: str = strings.concat(source, "/cmd/scoped");
|
||||
let repeated: str = strings.concat(source, "/cmd/repeated");
|
||||
let commitcodec: str = strings.concat(source, "/commit/codec");
|
||||
let commitapp: str = strings.concat(source, "/cmd/commit");
|
||||
let leafbad: str = strings.concat(source, "/cmd/leafbad");
|
||||
let leak: str = strings.concat(source, "/cmd/leak");
|
||||
let duplicate: str = strings.concat(source, "/cmd/duplicate");
|
||||
@@ -7895,7 +7897,8 @@ fn runtimepath(relative: str) str = {
|
||||
"/vend/vendor/short/codec");
|
||||
let vendorclient: str = strings.concat(source, "/vend/client");
|
||||
let dirs: []str = [source, tools, codec, bridge, direct, app, scopeone,
|
||||
scopetwo, scoped, repeated, leafbad, leak, duplicate, collision,
|
||||
scopetwo, scoped, repeated, commitcodec, commitapp, leafbad, leak,
|
||||
duplicate, collision,
|
||||
crosscollision, conflict, leafmain, program, leafmainuser, programuser, testcodec,
|
||||
testhelper, vendored, vendorclient];
|
||||
let di: i32 = 0;
|
||||
@@ -7909,6 +7912,12 @@ fn runtimepath(relative: str) str = {
|
||||
"export fn value() i32 = { return 42; };\n");
|
||||
let codecfile: str = strings.concat(codec, "/codec.ww");
|
||||
writefile(codecfile, wirebody);
|
||||
let commitcodecfile: str = strings.concat(commitcodec, "/codec.ww");
|
||||
let commitappfile: str = strings.concat(commitapp, "/main.ww");
|
||||
writefile(commitcodecfile, wirebody);
|
||||
writefile(commitappfile, strings.concat(
|
||||
"package main;\nimport commit.codec;\n",
|
||||
"fn main() i32 = { return wire.value(); };\n"));
|
||||
writefile(strings.concat(bridge, "/bridge.ww"), strings.concat(
|
||||
"package bridge;\nimport acme.codec;\n",
|
||||
// WW retains its direct-import bare-declaration convenience. It is
|
||||
@@ -8014,7 +8023,15 @@ fn runtimepath(relative: str) str = {
|
||||
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
|
||||
"\"$WW_NAME_COMPILER_TRACE\"; done\n",
|
||||
"printf '\\n' >> \"$WW_NAME_COMPILER_TRACE\"\n",
|
||||
"exec \"$WW_NAME_REAL_COMPILER\" \"$@\"\n"));
|
||||
"\"$WW_NAME_REAL_COMPILER\" \"$@\"\n",
|
||||
"status=$?\n",
|
||||
"if [ \"$status\" -eq 0 ] && ",
|
||||
"[ -n \"$WW_COMMIT_BLOCK_STAMP\" ]; then\n",
|
||||
" mv -- \"$WW_COMMIT_BLOCK_STAMP\" ",
|
||||
"\"$WW_COMMIT_BLOCK_STAMP.saved\" || exit 97\n",
|
||||
" mkdir -- \"$WW_COMMIT_BLOCK_STAMP\" || exit 98\n",
|
||||
"fi\n",
|
||||
"exit \"$status\"\n"));
|
||||
|
||||
let stages: []str = ["ww", "ww_ww"];
|
||||
let compilers: []str = ["w6c", "w6c_ww"];
|
||||
@@ -8032,6 +8049,16 @@ fn runtimepath(relative: str) str = {
|
||||
strings.concat(root, "/ww-scoped")];
|
||||
let repeatedbins: []str = [strings.concat(root, "/c-repeated"),
|
||||
strings.concat(root, "/ww-repeated")];
|
||||
let commitworks: []str = [strings.concat(root, "/c-commit-work"),
|
||||
strings.concat(root, "/ww-commit-work")];
|
||||
let commitcoldbins: []str = [strings.concat(root, "/c-commit-cold"),
|
||||
strings.concat(root, "/ww-commit-cold")];
|
||||
let commitblockbins: []str = [strings.concat(root, "/c-commit-block"),
|
||||
strings.concat(root, "/ww-commit-block")];
|
||||
let commitrejectbins: []str = [strings.concat(root, "/c-commit-reject"),
|
||||
strings.concat(root, "/ww-commit-reject")];
|
||||
let commitfixedbins: []str = [strings.concat(root, "/c-commit-fixed"),
|
||||
strings.concat(root, "/ww-commit-fixed")];
|
||||
let leafmainbins: []str = [strings.concat(root, "/c-leafmain"),
|
||||
strings.concat(root, "/ww-leafmain")];
|
||||
let vendorbins: []str = [strings.concat(root, "/c-vendor"),
|
||||
@@ -8053,13 +8080,22 @@ fn runtimepath(relative: str) str = {
|
||||
let scopedtraceref: str = "";
|
||||
let repeatedtraceref: str = "";
|
||||
let changedtraceref: str = "";
|
||||
let commitfailref: str = "";
|
||||
let commitpreflightref: str = "";
|
||||
let commitbindingref: str = "";
|
||||
let commitbinref: str = "";
|
||||
let initialwwiref: str = "";
|
||||
let testoutref: str = "";
|
||||
let baseenv: []str = os.getenvs();
|
||||
let si: i32 = 0;
|
||||
for (si < stages.len) {
|
||||
rewritefile(codecfile, wirebody);
|
||||
rewritefile(commitcodecfile, wirebody);
|
||||
rewritefile(commitappfile, strings.concat(
|
||||
"package main;\nimport commit.codec;\n",
|
||||
"fn main() i32 = { return wire.value(); };\n"));
|
||||
assert(os.mkdir(works[si], 448i32) == 0);
|
||||
assert(os.mkdir(commitworks[si], 448i32) == 0);
|
||||
writefile(traces[si], "");
|
||||
let env: []str = alloc([], (baseenv.len + 7): u64)!;
|
||||
let ei: i32 = 0;
|
||||
@@ -8071,7 +8107,9 @@ fn runtimepath(relative: str) str = {
|
||||
&& !strings.hasprefix(baseenv[ei],
|
||||
"WW_NAME_COMPILER_TRACE=")
|
||||
&& !strings.hasprefix(baseenv[ei],
|
||||
"WW_NAME_REAL_COMPILER=")) {
|
||||
"WW_NAME_REAL_COMPILER=")
|
||||
&& !strings.hasprefix(baseenv[ei],
|
||||
"WW_COMMIT_BLOCK_STAMP=")) {
|
||||
append(env, baseenv[ei]);
|
||||
};
|
||||
ei += 1;
|
||||
@@ -8122,6 +8160,127 @@ fn runtimepath(relative: str) str = {
|
||||
(30i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 42);
|
||||
|
||||
// A failed multi-file artifact rename may have published a new
|
||||
// interface before a later rename fails. It invalidates every old unit
|
||||
// voucher and the workdir identity, so the next request must reconsider
|
||||
// an importer even when the regenerated dependency export now compares
|
||||
// equal to that partially published interface.
|
||||
let commitcoldav: []str = [driver(stages[si]), "build", "-w",
|
||||
commitworks[si], "-I", source, "-o", commitcoldbins[si], commitapp];
|
||||
runcommandenv(root, strings.concat("name-commit-cold-", stages[si]),
|
||||
commitcoldav, env, (120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
let commitrun: []str = [commitcoldbins[si]];
|
||||
runcommand(root, strings.concat("name-commit-cold-run-", stages[si]),
|
||||
commitrun, (30i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 42);
|
||||
rewritefile(commitcodecfile, cablebody);
|
||||
let commitstamp: str = strings.concat(commitworks[si],
|
||||
"/.wwtool.stamp");
|
||||
let savedstamp: str = strings.concat(commitstamp, ".saved");
|
||||
let oldcommitwwi: str = readfile(strings.concat(commitworks[si],
|
||||
"/commit.codec.wwi"));
|
||||
let oldcommits: str = readfile(strings.concat(commitworks[si],
|
||||
"/commit.codec.s"));
|
||||
let oldcommito: str = readfile(strings.concat(commitworks[si],
|
||||
"/commit.codec.o"));
|
||||
let oldcommita: str = readfile(strings.concat(commitworks[si],
|
||||
"/commit.codec.a"));
|
||||
let blockenv: []str = alloc([], (env.len + 1): u64)!;
|
||||
let bei: i32 = 0;
|
||||
for (bei < env.len) { append(blockenv, env[bei]); bei += 1; };
|
||||
append(blockenv, strings.concat("WW_COMMIT_BLOCK_STAMP=", commitstamp));
|
||||
let commitblockav: []str = [driver(stages[si]), "build", "-w",
|
||||
commitworks[si], "-I", source, "-o", commitblockbins[si],
|
||||
commitapp];
|
||||
runcommandenv(root, strings.concat("name-commit-preflight-", stages[si]),
|
||||
commitblockav, blockenv,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(has(out.stderr, "ww: cannot invalidate package workdir\n"));
|
||||
if (si == 0) { commitpreflightref = strings.dup(out.stderr); }
|
||||
else { assert(same(commitpreflightref, out.stderr)); };
|
||||
assert(same(oldcommitwwi, readfile(strings.concat(commitworks[si],
|
||||
"/commit.codec.wwi"))));
|
||||
assert(same(oldcommits, readfile(strings.concat(commitworks[si],
|
||||
"/commit.codec.s"))));
|
||||
assert(same(oldcommito, readfile(strings.concat(commitworks[si],
|
||||
"/commit.codec.o"))));
|
||||
assert(same(oldcommita, readfile(strings.concat(commitworks[si],
|
||||
"/commit.codec.a"))));
|
||||
assert(!os.exists(strings.concat(commitworks[si],
|
||||
"/commit.codec.unit.ww")));
|
||||
assert(!os.exists(commitblockbins[si]));
|
||||
assert(os.rmdir(commitstamp) == 0);
|
||||
assert(os.rename(savedstamp, commitstamp) == 0);
|
||||
|
||||
// With the stamp preflight restored, force a later artifact rename to
|
||||
// fail after the changed interface has already been published.
|
||||
let blockedasm: str = strings.concat(commitworks[si],
|
||||
"/commit.codec.s");
|
||||
assert(os.remove(blockedasm) == 0);
|
||||
assert(os.mkdir(blockedasm, 448i32) == 0);
|
||||
let commitrejectav: []str = [driver(stages[si]), "build", "-w",
|
||||
commitworks[si], "-I", source, "-o", commitrejectbins[si],
|
||||
commitapp];
|
||||
runcommandenv(root, strings.concat("name-commit-partial-", stages[si]),
|
||||
commitrejectav, env,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(has(out.stderr, "ww: cannot commit commit.codec\n"));
|
||||
if (si == 0) { commitfailref = strings.dup(out.stderr); }
|
||||
else { assert(same(commitfailref, out.stderr)); };
|
||||
assert(has(readfile(strings.concat(commitworks[si],
|
||||
"/commit.codec.wwi")),
|
||||
"//ww:module commit.codec\npackage cable;\n"));
|
||||
assert(!os.exists(strings.concat(commitworks[si],
|
||||
"/commit.codec.unit.ww")));
|
||||
assert(!os.exists(strings.concat(commitworks[si],
|
||||
"/cmd.commit.unit.ww")));
|
||||
assert(!os.exists(strings.concat(commitworks[si], "/.wwtool.stamp")));
|
||||
let partialsuffixes: []str = [".unit.new", ".wwi.new", ".s.new",
|
||||
".o.new", ".a.new"];
|
||||
let psi: i32 = 0;
|
||||
for (psi < partialsuffixes.len) {
|
||||
assert(!os.exists(strings.concat(commitworks[si],
|
||||
"/commit.codec", partialsuffixes[psi])));
|
||||
psi += 1;
|
||||
};
|
||||
assert(!os.exists(commitrejectbins[si]));
|
||||
assert(os.rmdir(blockedasm) == 0);
|
||||
rewritefile(traces[si], "");
|
||||
runcommandenv(root, strings.concat("name-commit-reconsider-", stages[si]),
|
||||
commitrejectav, env,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(has(out.stderr, "undefined: wire"));
|
||||
let ncommitbinding: str = normalizedtrace(out.stderr,
|
||||
strings.concat(commitworks[si], "/"), commitrejectbins[si]);
|
||||
if (si == 0) { commitbindingref = strings.dup(ncommitbinding); }
|
||||
else { assert(same(commitbindingref, ncommitbinding)); };
|
||||
assert(has(readfile(traces[si]), "/cmd.commit.unit.new"));
|
||||
assert(os.exists(strings.concat(commitworks[si],
|
||||
"/commit.codec.unit.ww")));
|
||||
assert(!os.exists(strings.concat(commitworks[si],
|
||||
"/cmd.commit.unit.ww")));
|
||||
assert(!os.exists(commitrejectbins[si]));
|
||||
rewritefile(commitappfile, strings.concat(
|
||||
"package main;\nimport commit.codec;\n",
|
||||
"fn main() i32 = { return cable.value(); };\n"));
|
||||
let commitfixedav: []str = [driver(stages[si]), "build", "-w",
|
||||
commitworks[si], "-I", source, "-o", commitfixedbins[si], commitapp];
|
||||
runcommandenv(root, strings.concat("name-commit-fixed-", stages[si]),
|
||||
commitfixedav, env,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
let commitfixedrun: []str = [commitfixedbins[si]];
|
||||
runcommand(root, strings.concat("name-commit-fixed-run-", stages[si]),
|
||||
commitfixedrun, (30i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 42);
|
||||
let commitbinbytes: str = readfile(commitfixedbins[si]);
|
||||
if (si == 0) { commitbinref = strings.dup(commitbinbytes); }
|
||||
else { assert(same(commitbinref, commitbinbytes)); };
|
||||
|
||||
// The same declared qualifier belongs to each importing source file,
|
||||
// not to the package-wide namespace.
|
||||
rewritefile(traces[si], "");
|
||||
|
||||
Reference in New Issue
Block a user