ww: preserve command package identities
This commit is contained in:
@@ -2609,7 +2609,8 @@ fn localidentity(dir: str, leaf: str) str = {
|
||||
let base: str = strings.concat(source, "/ww_root_parity_base_7f3");
|
||||
let left: str = strings.concat(source, "/ww_root_parity_left_7f3");
|
||||
let right: str = strings.concat(source, "/ww_root_parity_right_7f3");
|
||||
let target: str = strings.concat(source, "/main");
|
||||
let rootidentity: str = "ww_root_parity_target_7f3";
|
||||
let target: str = strings.concat(source, "/", rootidentity);
|
||||
let tools: str = strings.concat(root, "/tool wrappers");
|
||||
assert(os.mkdir(source, 448i32) == 0);
|
||||
assert(os.mkdir(runtime, 448i32) == 0);
|
||||
@@ -2703,9 +2704,11 @@ fn localidentity(dir: str, leaf: str) str = {
|
||||
let workroot: str = strings.concat(bin, ".sepwork");
|
||||
let work: str = strings.concat(workroot, "/");
|
||||
let artifacts: []str = ["ww_root_parity_base_7f3",
|
||||
"ww_root_parity_left_7f3", "ww_root_parity_right_7f3", "main"];
|
||||
"ww_root_parity_left_7f3", "ww_root_parity_right_7f3",
|
||||
rootidentity];
|
||||
let unitartifacts: []str = ["ww_root_parity_base_7f3",
|
||||
"ww_root_parity_left_7f3", "ww_root_parity_right_7f3", "main"];
|
||||
"ww_root_parity_left_7f3", "ww_root_parity_right_7f3",
|
||||
rootidentity];
|
||||
let wantunits: []str = [strings.concat(
|
||||
"//ww:module-reset ww_root_parity_base_7f3\n", basea,
|
||||
"\n//ww:module-reset ww_root_parity_base_7f3\n", basez, "\n"),
|
||||
@@ -2713,7 +2716,8 @@ fn localidentity(dir: str, leaf: str) str = {
|
||||
leftbody, "\n"),
|
||||
strings.concat("//ww:module-reset ww_root_parity_right_7f3\n",
|
||||
rightbody, "\n"),
|
||||
strings.concat("//ww:module-reset main\n", rootbody, "\n")];
|
||||
strings.concat("//ww:module-reset ", rootidentity, "\n", rootbody,
|
||||
"\n")];
|
||||
let referenceunits: []str = ["", "", "", ""];
|
||||
let referenceexports: []str = ["", "", "", ""];
|
||||
let referencearchives: []str = ["", "", "", ""];
|
||||
@@ -2807,6 +2811,11 @@ fn localidentity(dir: str, leaf: str) str = {
|
||||
".wwi"));
|
||||
let archive: str = readfile(strings.concat(work, artifacts[ai],
|
||||
".a"));
|
||||
if (ai == 3) {
|
||||
assert(strings.hasprefix(exportf, strings.concat("package ",
|
||||
rootidentity, ";\n")));
|
||||
assert(!strings.hasprefix(exportf, "package main;\n"));
|
||||
};
|
||||
if (si == 0) {
|
||||
referenceexports[ai] = strings.dup(exportf);
|
||||
referencearchives[ai] = strings.dup(archive);
|
||||
@@ -2843,16 +2852,28 @@ fn localidentity(dir: str, leaf: str) str = {
|
||||
"ww_root_parity_left_7f3.wwi><--import>",
|
||||
"<ww_root_parity_right_7f3><", work,
|
||||
"ww_root_parity_right_7f3.wwi><-I><", work,
|
||||
"main.wwi><-o><", work,
|
||||
"main.s><", work, "main.unit.ww>");
|
||||
rootidentity, ".wwi><-o><", work,
|
||||
rootidentity, ".s><", work, rootidentity, ".unit.ww>");
|
||||
assert(same(linecontaining(ctrace,
|
||||
"ww_root_parity_base_7f3.unit.ww"), baseline));
|
||||
assert(same(linecontaining(ctrace,
|
||||
"ww_root_parity_left_7f3.unit.ww"), leftline));
|
||||
assert(same(linecontaining(ctrace,
|
||||
"ww_root_parity_right_7f3.unit.ww"), rightline));
|
||||
assert(same(linecontaining(ctrace, "main.unit.ww"), rootline));
|
||||
assert(same(linecontaining(ctrace, strings.concat(rootidentity,
|
||||
".unit.ww")), rootline));
|
||||
assert(!has(rootline, "ww_root_parity_base_7f3.wwi"));
|
||||
// The primary command declaration is accepted only when the compiler
|
||||
// receives command classification from --entry. Imported interfaces and
|
||||
// ordinary package compiles retain strict identity-leaf validation.
|
||||
let rejectwwi: str = strings.concat(root, "/reject-", tags[si], ".wwi");
|
||||
let rejectasm: str = strings.concat(root, "/reject-", tags[si], ".s");
|
||||
let rejectav: []str = [driver(compilers[si]), "-c", "-I", rejectwwi,
|
||||
"-o", rejectasm, strings.concat(work, rootidentity, ".unit.ww")];
|
||||
runcommand(root, strings.concat("command-without-entry-", tags[si]),
|
||||
rejectav, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(has(out.stderr, "does not match import path"));
|
||||
assert(occurrences(atrace, "\n") == 4);
|
||||
ai = 0;
|
||||
for (ai < artifacts.len) {
|
||||
@@ -2864,7 +2885,7 @@ fn localidentity(dir: str, leaf: str) str = {
|
||||
};
|
||||
assert(occurrences(ltrace, "\n") == 1);
|
||||
assert(has(ltrace, strings.concat("BEGIN<-o><", bin, "><", work,
|
||||
"main.a>")));
|
||||
rootidentity, ".a>")));
|
||||
ai = 0;
|
||||
for (ai < artifacts.len) {
|
||||
assert(occurrences(ltrace, strings.concat("<", work, artifacts[ai],
|
||||
@@ -2935,6 +2956,138 @@ fn localidentity(dir: str, leaf: str) str = {
|
||||
clean(root);
|
||||
};
|
||||
|
||||
@test fn command_package_test_variants_keep_canonical_identity() void = {
|
||||
let root: str = fresh();
|
||||
let source: str = strings.concat(root, "/source");
|
||||
let target: str = strings.concat(source, "/cmdtool");
|
||||
let importer: str = strings.concat(source, "/importer");
|
||||
let wrapper: str = strings.concat(root, "/command-w6c.sh");
|
||||
assert(os.mkdir(source, 448i32) == 0);
|
||||
assert(os.mkdir(target, 448i32) == 0);
|
||||
assert(os.mkdir(importer, 448i32) == 0);
|
||||
writefile(strings.concat(target, "/main.ww"), strings.concat(
|
||||
"package main;\n",
|
||||
"export fn value() i32 = { return 41; };\n",
|
||||
"fn main() i32 = { return 0; };\n"));
|
||||
writefile(strings.concat(target, "/internal_test.ww"), strings.concat(
|
||||
"package main;\n",
|
||||
"@test fn command_internal() void = { assert(value() == 41); };\n"));
|
||||
writefile(strings.concat(target, "/external_test.ww"), strings.concat(
|
||||
"package main_test;\n",
|
||||
"import cmdtool;\n",
|
||||
"@test fn command_external() void = { ",
|
||||
"assert(cmdtool.value() == 41); };\n"));
|
||||
writefile(strings.concat(importer, "/importer.ww"), strings.concat(
|
||||
"package importer;\n",
|
||||
"import cmdtool;\n",
|
||||
"export fn value() i32 = { return cmdtool.value(); };\n"));
|
||||
writeexecutable(wrapper, strings.concat(
|
||||
"#!/bin/sh\n",
|
||||
"printf 'BEGIN' >> \"$WW_COMMAND_COMPILER_TRACE\"\n",
|
||||
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
|
||||
"\"$WW_COMMAND_COMPILER_TRACE\"; done\n",
|
||||
"printf '\\n' >> \"$WW_COMMAND_COMPILER_TRACE\"\n",
|
||||
"exec \"$WW_COMMAND_REAL_COMPILER\" \"$@\"\n"));
|
||||
|
||||
let stages: []str = ["ww", "ww_ww"];
|
||||
let compilers: []str = ["w6c", "w6c_ww"];
|
||||
let artifacts: []str = ["cmdtool", "cmdtool-internal-test",
|
||||
"cmdtool_test-external-test"];
|
||||
let suffixes: []str = [".unit.ww", ".wwi", ".a"];
|
||||
let reference: []str = ["", "", "", "", "", "", "", "", ""];
|
||||
let samebin: str = strings.concat(target, "/main.test");
|
||||
let externalbin: str = strings.concat(target, "/main_test.test");
|
||||
let workroot: str = strings.concat(samebin, ".sepwork");
|
||||
let work: str = strings.concat(workroot, "/");
|
||||
let baseenv: []str = os.getenvs();
|
||||
let si: i32 = 0;
|
||||
for (si < stages.len) {
|
||||
let trace: str = strings.concat(root, "/", stages[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_W6C=")
|
||||
&& !strings.hasprefix(baseenv[ei],
|
||||
"WW_COMMAND_COMPILER_TRACE=")
|
||||
&& !strings.hasprefix(baseenv[ei],
|
||||
"WW_COMMAND_REAL_COMPILER=")) {
|
||||
append(env, baseenv[ei]);
|
||||
};
|
||||
ei += 1;
|
||||
};
|
||||
append(env, strings.concat("WW_W6C=", wrapper));
|
||||
append(env, strings.concat("WW_COMMAND_COMPILER_TRACE=", trace));
|
||||
append(env, strings.concat("WW_COMMAND_REAL_COMPILER=",
|
||||
driver(compilers[si])));
|
||||
let av: []str = [driver(stages[si]), "test", "-c", "-I", source,
|
||||
target];
|
||||
let out: commandout;
|
||||
runcommandenv(root, strings.concat("command-variants-", stages[si]), av,
|
||||
env, (120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stderr.len == 0);
|
||||
|
||||
let ctrace: str = readfile(trace);
|
||||
let ai: i32 = 0;
|
||||
for (ai < artifacts.len) {
|
||||
let line: str = linecontaining(ctrace,
|
||||
strings.concat(artifacts[ai], ".unit.ww"));
|
||||
assert(has(line, "<--command-package>"));
|
||||
let sj: i32 = 0;
|
||||
for (sj < suffixes.len) {
|
||||
let body: str = readfile(strings.concat(work, artifacts[ai],
|
||||
suffixes[sj]));
|
||||
let ri: i32 = ai * suffixes.len + sj;
|
||||
if (si == 0) { reference[ri] = strings.dup(body); }
|
||||
else { assert(same(reference[ri], body)); };
|
||||
sj += 1;
|
||||
};
|
||||
ai += 1;
|
||||
};
|
||||
assert(has(readfile(strings.concat(work, "cmdtool.unit.ww")),
|
||||
"//ww:module-reset cmdtool\n"));
|
||||
assert(has(readfile(strings.concat(work,
|
||||
"cmdtool-internal-test.unit.ww")),
|
||||
"//ww:module-reset cmdtool\n"));
|
||||
assert(has(readfile(strings.concat(work,
|
||||
"cmdtool_test-external-test.unit.ww")),
|
||||
"//ww:module-reset cmdtool_test\n"));
|
||||
|
||||
let runav: []str = [samebin, "-package=main"];
|
||||
runcommand(root, strings.concat("command-internal-run-", stages[si]),
|
||||
runav, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(has(out.stdout, "command_internal ... ok\n"));
|
||||
let externalav: []str = [externalbin, "-package=main_test"];
|
||||
runcommand(root, strings.concat("command-external-run-", stages[si]),
|
||||
externalav, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(has(out.stdout, "command_external ... ok\n"));
|
||||
|
||||
// The same command action is not generally source-importable. It is
|
||||
// classified before leaf validation so this Go-like diagnostic is stable,
|
||||
// and graph failure occurs before any compiler invocation.
|
||||
clean(trace);
|
||||
writefile(trace, "");
|
||||
let importout: str = strings.concat(root, "/importer-", stages[si], ".a");
|
||||
let importav: []str = [driver(stages[si]), "build", "-p", "-I", source,
|
||||
"-o", importout, importer];
|
||||
runcommandenv(root, strings.concat("command-import-", stages[si]),
|
||||
importav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(has(out.stderr,
|
||||
"package cmdtool is a program, not an importable package\n"));
|
||||
assert(readfile(trace).len == 0);
|
||||
|
||||
clean(workroot);
|
||||
clean(samebin);
|
||||
clean(externalbin);
|
||||
si += 1;
|
||||
};
|
||||
clean(root);
|
||||
};
|
||||
|
||||
@test fn package_graph_diagnostics_are_stable() void = {
|
||||
let root: str = fresh();
|
||||
let missing: str = strings.concat(root, "/missing");
|
||||
|
||||
Reference in New Issue
Block a user