fix: ignore hidden named source operands

This commit is contained in:
2026-08-22 19:28:54 +09:00
parent 6279d46652
commit 3922f1c34e
6 changed files with 627 additions and 0 deletions

View File

@@ -7136,6 +7136,38 @@ basename_no_ext(const char *path, char *out, size_t outsz)
if (dot && strcmp(dot, ".ww") == 0) *dot = '\0';
}
/* Go's named-file package still applies matchFile's unconditional basename
* exclusion before UseAllFiles, platform suffixes, source parsing, or test-file
* classification. Keep this predicate on the public operand spelling: a
* hidden parent does not hide a visible named file, while a hidden symlink
* spelling remains hidden regardless of its non-directory target kind. */
static int
source_operand_ignored(const char *path)
{
struct stat st;
size_t n = strlen(path);
if (n < 3 || strcmp(path + n - 3, ".ww") != 0) return 0;
if (stat(path, &st) != 0 || S_ISDIR(st.st_mode)) return 0;
const char *base = strrchr(path, '/');
base = base ? base + 1 : path;
return base[0] == '.' || base[0] == '_';
}
static void
source_operand_no_sources(const char *path)
{
const char *slash = strrchr(path, '/');
fputs("ww: ", stderr);
if (slash == NULL) {
fputc('.', stderr);
} else if (slash == path) {
fputc('/', stderr);
} else {
(void)fwrite(path, 1, (size_t)(slash - path), stderr);
}
fputs(": directory contains no WW package sources\n", stderr);
}
/* Go's build -o directory branch follows an existing destination through
* stat, and a trailing platform separator declares a directory which the
* request may need to create. WW's platform separator is '/'. */
@@ -7442,6 +7474,11 @@ do_build(int argc, char **argv)
}
struct stat requested;
int literal = stat(src, &requested) == 0;
if (source_operand_ignored(src)) {
source_operand_no_sources(src);
free(incs);
return 1;
}
char resolved[PATH_MAX];
int is_dir = 0;
if (!resolve_module(src, incs, resolved, sizeof resolved, &is_dir)) {
@@ -7988,6 +8025,29 @@ do_test(int argc, char **argv)
}
}
int discard_output = strcmp(outstem, "/dev/null") == 0;
if (strstr(target, "...") == NULL && source_operand_ignored(target)) {
if (nproducts != 0 && outstem[0]) {
fprintf(stderr,
"ww test: package-test products reject -o\n");
return 2;
}
if (nproducts != 0) {
fprintf(stderr,
"ww test: package-test variant needs one directory\n");
return 2;
}
if (packageopts) {
fprintf(stderr,
"ww test: package options need a directory\n");
return 2;
}
source_operand_no_sources(target);
if (src != NULL && !compileonly && !emit_asm)
fputs("FAIL\n", stdout);
free(products);
free(incs);
return 1;
}
if (pattern != NULL) {
struct stat first;
if (stat(target, &first) != 0 || !S_ISREG(first.st_mode)) {

View File

@@ -9955,6 +9955,131 @@ artifact-layout, harness-protocol, cache, database, or publication field.
Build workdir format remains `18`, test workdir format remains `19`, semantic
storage format remains `3`, and no test-result cache is introduced.
### 11.50 Implemented named-source leading-dot/underscore eligibility
An explicitly named raw `.ww` source now observes the same unconditional
basename exclusion as a named `.go` source in Go 1.26.5. This closes the gap in
WW's existing single-source command route: a final requested basename beginning
`.` or `_` is not a package source, even though named sources otherwise bypass
directory-only target-suffix selection. Directory selection already enforced
this rule and remains unchanged.
#### Pinned Go evidence and applicability
The reference is official Go 1.26.5 at commit
`c19862e5f8415b4f24b189d065ed739517c548ba`:
- `PackagesAndErrors` recognizes an existing `.go` operand and routes the
complete named list to `GoFilesPackage`
([`cmd/go/internal/load/pkg.go`, lines 29032918](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L2903-L2918)).
`GoFilesPackage` enables `UseAllFiles`, presents only the named `FileInfo`
entries through a synthetic directory, and loads one command-line package
([lines 32443315](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L3244-L3315)).
- `go/build.Import` passes each synthetic entry through `Context.matchFile`
([`go/build/build.go`, lines 886914](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L886-L914)).
`matchFile` rejects a name beginning `_` or `.` before extension, target
suffix, open, imports, or build constraints; that branch precedes the
`UseAllFiles` condition
([lines 14381509](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1438-L1509)).
A package with no remaining source category returns `NoGoError`
([lines 10761082](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1076-L1082));
the command loader presents the case as `no Go files`
([`cmd/go/internal/load/pkg.go`, lines 250270](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L250-L270)).
- Build reports load errors before installation/action construction
([`cmd/go/internal/work/build.go`, lines 697728](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L697-L728)).
Test uses the same loader
([`cmd/go/internal/test/test.go`, lines 703719](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L703-L719))
and turns its error into package setup failure before constructing a runnable
([lines 10151050](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1015-L1050)).
- Official command testdata explicitly records that `_cgo_yy.go` named on the
command line is ignored and permits the exact `no Go files` result
([`cgo_bad_directives.txt`, lines 1123](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/cgo_bad_directives.txt#L11-L23)).
`import_ignore.txt` independently proves a dot file contributes no import
([lines 111](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/import_ignore.txt#L1-L11)).
The rule honestly applies to WW's local literal `.ww` operand. It adds no
module, manifest, registry, network, generalized import, or build-expression
surface. This section is deliberately bounded to the existing single raw
source target. Multiple named sources as one package and visible
`*_test.ww` exclusion from `ww build` remain separate open semantics; when a
future source-set loader admits multiple names, it must apply this same rule to
each requested basename.
#### Source, package, and import ownership
The twin public drivers own one allocation-free operand predicate after
existing CLI-shape checks and a successful requested-path `Stat`, but before
logical resolution or graph entry. It requires an original spelling ending
exactly `.ww`, then examines only the final requested basename. A hidden parent
containing visible `main.ww` does not
exclude the named source. A requested hidden symlink spelling is excluded even
when its target is visible or non-regular, while a visible requested spelling
remains eligible even when its target basename is hidden. This follows the
`FileInfo.Name` seen
by Go's synthetic named-file directory: Unix `Stat` follows the target but
fills `Name` from the requested path
([`os/stat_unix.go`, lines 2838](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/os/stat_unix.go#L28-L38),
[`os/stat_linux.go`, lines 1330](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/os/stat_linux.go#L13-L30)).
Physical target paths do not become identity.
Prefix exclusion precedes every later classifier. `_main_test.ww` and
`.main_test.ww` are absent before production/test partitioning. A hidden
`_main_windows.ww` is absent, but a visible `main_windows.ww` named directly
remains eligible because the named-file analogue uses `UseAllFiles`; directory
platform filtering is unchanged. Logical operands without a `.ww` suffix,
directory and recursive requests, imports, and `ww run` retain their existing
routes.
An excluded operand creates no package clause, declaration, production/test
variant, or top-level state. Its bytes are not decoded or parsed: malformed
UTF-8, NUL, BOM, missing/invalid package clauses, late imports, missing imports,
unused imports, cycles, `internal`/vendor rules, and checker diagnostics cannot
resurrect it or outrank selection. It contributes no qualifier, import-use
obligation, edge, canonical dotted identity, initializer, or link closure. The
lexical parent printed by the diagnostic is presentation metadata only and is
never package, import, graph, action, symbol, `.wwi`, artifact, publication, or
persistence identity.
#### Observable command and lifecycle behavior
`ww build HIDDEN.ww` exits 1 with empty standard output and
`ww: PARENT: directory contains no WW package sources` on standard error.
An ordinary explicit running `ww test HIDDEN.ww` adds its established exact
command-owned `FAIL` line on standard output; compile-only and assembly-only
test requests do not. With no slash, `PARENT` is `.`, a root child uses `/`,
and otherwise it is the requested lexical bytes before the final slash. CLI
flag/path-length errors and the existing raw-test directory-only package-option
shape keep their precedence. A failed requested-path `Stat` retains ordinary
target/logical resolution; for an existing non-directory raw operand,
no-source selection precedes logical resolution, output-destination preflight,
and all source, producer, publication, and runtime diagnostics. Exact
`/dev/null` does not suppress the load failure.
No root/dependency action, test support, generated main, compiler, assembler,
archiver, linker, harness, test child, or program process starts. Cold rejection
creates no default or explicit output, workdir, adjacent `.sepwork`, unit,
`.wwi`, assembly, object, archive, init artifact, binary, status, stage, capture,
result, transaction, or private temporary directory. Warm rejection starts no
transaction and preserves every prior work-artifact and public/retained byte.
It leaves no `.new`, `.install`, `.wwtxn.*`, or recovery residue. Producer,
runtime, publication-only, cleanup-only, signal, timeout, and descendant
semantics for visible inputs are unchanged.
The predicate is request-local and creates no shared state, process group,
lock, or interruption owner, so overlapping hidden and visible requests remain
isolated. Cstage and WWstage must agree byte-for-byte on status, stdout, stderr,
and complete artifact absence; representative visible named sources retain
binary and semantic-artifact identity. The focused native
`named_source_prefixes_are_ignored` observer owns both prefixes, build/test and
compile-only paths, prefix-before-test/platform precedence, requested symlink
spelling, hidden-parent/visible-basename and wrong-platform controls, unread
malformed/import bytes, cold cleanup, warm preservation/restoration, residue,
and stage parity.
No serialized format changes. Build workdir format remains `18`, test workdir
format remains `19`, semantic storage format remains `3`, and there is no test
result cache.
## 12. Candidate architectures and hard-gate decision
Five candidates were developed as coherent systems, not as feature bins.

View File

@@ -319,6 +319,22 @@ ImportPath = ident { "." ident } .
delegated graph-import scan or tools. An ordinary build compares production
names only; one test product compares its production, same-package test, and
external-test selections without merging their units.
- A single existing raw `.ww` operand is also subject to the unconditional
leading-name rule: if its final requested basename begins `.` or `_`, it is
ignored before the source is opened. Named raw sources otherwise retain their
existing all-files behavior, so a visible wrong-platform suffix remains
eligible. Only the requested basename participates: a hidden parent does not
hide visible `main.ww`, a hidden symlink spelling stays hidden for any
existing non-directory target, and a visible symlink spelling stays eligible.
The excluded operand creates no package, declaration, import binding/edge,
action, artifact, initialization, test,
publication, or persistent state. `ww build` reports the existing
`directory contains no WW package sources` condition; an explicit running
raw `ww test` also emits its command-owned `FAIL`, while `-c` and `-S` do not.
This rule does not add multiple named-source package support, does not change
visible `*_test.ww` handling, and does not apply to logical operands,
directory/recursive requests, imports, or `ww run`. The diagnostic parent is
presentation metadata and never canonical identity.
- `import acme.codec;` loads the canonical package `acme.codec`. If that
package declares `package wire;`, the importing file sees its exported names
as `wire.Name`; `codec.Name` is not an additional binding. An explicit alias

View File

@@ -219,6 +219,26 @@ every `-j` level, and `-j 1` — the default — matches the former sequential
run loop exactly. Measured on the 31-package `lib/...` walk:
7.0s sequential, 2.4s at `-j 4`.
The raw single-source compatibility route applies package-source eligibility
before it invokes the compiler or harness. An existing operand ending `.ww`
whose final requested basename begins `.` or `_` is ignored exactly as it is by
directory discovery, even when the name also ends `_test.ww`; the file is not
opened and cannot contribute a test descriptor, package declaration, import,
variant, graph action, diagnostic, artifact, retained binary, or persistent
state. A normal explicit running request exits 1 with exact `FAIL\n` stdout and
the driver's `directory contains no WW package sources` stderr; `-c` and `-S`
omit the final marker. Visible wrong-platform raw names remain eligible, and
only the requested basename matters for symlinks (including non-regular
targets) and hidden parent directories.
CLI/target and the existing raw package-option shape retain precedence. Cold
rejection creates no work or temporary product; warm rejection preserves prior
work and public bytes without transaction residue. The focused
`named_source_prefixes_are_ignored` package observer proves these rules in both
driver stages, including malformed/import precedence, prefix-before-test and
platform classification, symlink spelling, output rollback, residue, and
diagnostic/artifact parity. Directory package coordination and test process,
filter, timeout, signal, and descendant topology are unchanged.
List mode uses that same product process and initialization boundary but starts
no per-test child. The shared language harness emits only selected qualified
test names, one per line in descriptor order. A valid filter selecting no tests

View File

@@ -8564,6 +8564,40 @@ fn basenameoff(p: *u8, plen: u64) u64 = {
return start;
};
// A named Go source still passes through matchFile's leading-dot/underscore
// exclusion even when UseAllFiles bypasses platform suffixes and build tags.
// Inspect the public operand spelling so a hidden parent is not source identity
// and a hidden symlink spelling cannot be resurrected by a non-directory
// target's name or file kind.
fn sourceoperandignored(path: *u8) bool = {
if (!cstrendswithlit(path, ".ww")) { return false; };
let fi: os.filestat;
match (os.stat(&fi, pathstr(path))) {
case void => {
let typ: u32 = (fi.mode: u32) & 61440u32;
if (typ == os.mode.DIR: u32) { return false; };
};
case let e: os.oserror => return false;
};
let n: u64 = cstrlen(path);
let base: u64 = basenameoff(path, n);
return path[base] == '.' || path[base] == '_';
};
fn sourceoperandnosources(path: *u8) void = {
let n: u64 = cstrlen(path);
let base: u64 = basenameoff(path, n);
cerr("ww: ");
if (base == 0u64) {
cerr(".");
} else { if (base == 1u64) {
cerr("/");
} else {
os.write(os.STDERR_FILENO, path, base - 1u64);
}; };
cerr(": directory contains no WW package sources\n");
};
fn arenadupcstr(src: *u8, plen: u64) *u8 = {
let buf: []u8 = alloc([], plen + 1u64)!;
let i: u64 = 0u64;
@@ -8914,6 +8948,10 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
case void => requestedliteral = true;
case let e: os.oserror => void;
};
if (sourceoperandignored(src)) {
sourceoperandnosources(src);
return 1;
};
let isdir: i32 = 0;
let resolved: *u8 = resolvemodule(selfdir, src, incs.ptr, &isdir);
if (resolved == nil) {
@@ -9792,6 +9830,26 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
producti += 1;
};
};
if (!strings.contains(pathstr(target), "...")
&& sourceoperandignored(target)) {
if (products.len != 0 && outstem != nil) {
cerr("ww test: package-test products reject -o\n");
return 2;
};
if (products.len != 0) {
cerr("ww test: package-test variant needs one directory\n");
return 2;
};
if (packageopts) {
cerr("ww test: package options need a directory\n");
return 2;
};
sourceoperandnosources(target);
if (targetindex >= 0 && compileonly == 0 && emitasm == 0) {
os.write(1, "FAIL\n".ptr, 5u64);
};
return 1;
};
if (patarg != nil) {
let first: os.filestat;
let firstregular: bool = false;

View File

@@ -987,6 +987,354 @@ fn cwdwritedata(dir: str, label: str) void = {
clean(root);
};
@test fn named_source_prefixes_are_ignored() void = {
let root: str = fresh();
let source: str = strings.concat(root, "/source");
let hiddenparent: str = strings.concat(source, "/.parent");
let symlinks: str = strings.concat(source, "/symlinks");
let warm: str = strings.concat(source, "/warm");
mkdirall(source); mkdirall(hiddenparent); mkdirall(symlinks); mkdirall(warm);
let maintext: str =
"package main;\nfn main() i32 = { return 0; };\n";
let testtext: str = strings.concat(
"package raw_windows_test;\n",
"@test fn selected() void = { assert(true); };\n");
let missingmain: str = strings.concat(
"package main;\nimport absent.pkg;\n",
"fn main() i32 = { return pkg.value(); };\n");
let missingtest: str = strings.concat(
"package missing_test;\nimport absent.pkg;\n",
"@test fn never() void = { abort(); };\n");
let malformed: str = "this source must never be opened {\n";
let hiddenbuild: str = strings.concat(source, "/_broken_windows_test.ww");
let dotbuild: str = strings.concat(source, "/.missing.ww");
let hiddentest: str = strings.concat(source,
"/_broken_windows_test.ww");
let dottest: str = strings.concat(source, "/.missing_test.ww");
let visiblewrong: str = strings.concat(source, "/visible_windows.ww");
let visiblewrongtest: str = strings.concat(source,
"/visible_windows_test.ww");
let hiddenparentmain: str = strings.concat(hiddenparent, "/main.ww");
let visibletarget: str = strings.concat(symlinks, "/target.ww");
let hiddentarget: str = strings.concat(symlinks, "/.target.ww");
let hiddenlink: str = strings.concat(symlinks, "/_link.ww");
let hiddendevice: str = strings.concat(symlinks, "/_device.ww");
let visiblelink: str = strings.concat(symlinks, "/visible-link.ww");
let warmvisible: str = strings.concat(warm, "/warm.ww");
let warmhidden: str = strings.concat(warm, "/_warm.ww");
writefile(hiddenbuild, malformed);
writefile(dotbuild, missingmain);
writefile(dottest, missingtest);
writefile(visiblewrong, maintext);
writefile(visiblewrongtest, testtext);
writefile(hiddenparentmain, maintext);
writefile(visibletarget, maintext);
writefile(hiddentarget, maintext);
assert(os.symlink(visibletarget, hiddenlink) == 0);
assert(os.symlink("/dev/null", hiddendevice) == 0);
assert(os.symlink(hiddentarget, visiblelink) == 0);
writefile(warmvisible, maintext);
let stages: []str = ["ww", "ww_ww"];
let tags: []str = ["c", "ww"];
let rootartifacts: []str = ["/__root.unit.ww", "/__root.wwi",
"/__root.s", "/__root.o", "/__root.a",
"/__root.init.unit.ww", "/__root.init.s", "/__root.init.o"];
let visiblebuildbin: str = "";
let visiblebuildartifacts: []str = alloc([], rootartifacts.len: u64)!;
let visibletestbin: str = "";
let visibletestartifacts: []str = alloc([], rootartifacts.len: u64)!;
let visibleteststdout: str = "";
let hiddendiagnostics: []str = alloc([], 20u64)!;
let si: i32 = 0;
for (si < stages.len) {
let prefix: str = strings.concat(tags[si], "-");
let coldwork: str = strings.concat(root, "/cold-work-", tags[si]);
let coldout: str = strings.concat(root, "/cold-output-", tags[si]);
let out: commandout;
// A final requested basename, rather than any parent component, owns
// Go's unconditional editor-temporary exclusion.
let av: []str = [driver(stages[si]), "build", "-w", coldwork,
"-o", coldout, "_broken_windows_test.ww"];
runcommanddir(root, strings.concat(prefix, "relative-hidden-build"),
source, av, (30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
let relativebuilddiag: str =
"ww: .: directory contains no WW package sources\n";
assert(out.stdout.len == 0 && same(out.stderr, relativebuilddiag)
&& !os.exists(coldwork) && !os.exists(coldout)
&& !os.exists(strings.concat(coldout, ".sepwork")));
append(hiddendiagnostics, strings.dup(out.stderr));
let dotbuildav: []str = [driver(stages[si]), "build", "-o",
strings.concat(root, "/dot-output-", tags[si]), dotbuild];
runcommand(root, strings.concat(prefix, "dot-missing-build"), dotbuildav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
let sourcediag: str = strings.concat("ww: ", source,
": directory contains no WW package sources\n");
assert(out.stdout.len == 0 && same(out.stderr, sourcediag)
&& !has(out.stderr, "absent.pkg")
&& !os.exists(strings.concat(root, "/dot-output-", tags[si]))
&& !os.exists(strings.concat(root, "/dot-output-", tags[si],
".sepwork")));
append(hiddendiagnostics, strings.dup(out.stderr));
let testcoldwork: str = strings.concat(root, "/cold-test-work-",
tags[si]);
let testcoldout: str = strings.concat(root, "/cold-test-output-",
tags[si]);
let hiddentestrunav: []str = [driver(stages[si]), "test", "-w",
testcoldwork, "-o",
testcoldout, hiddentest];
runcommand(root, strings.concat(prefix, "hidden-test-run"),
hiddentestrunav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(same(out.stdout, "FAIL\n") && same(out.stderr, sourcediag)
&& !has(out.stderr, "invalid or missing package clause")
&& !os.exists(testcoldwork) && !os.exists(testcoldout)
&& !os.exists(strings.concat(testcoldout, ".sepwork")));
append(hiddendiagnostics, strings.dup(out.stderr));
let compiled: str = strings.concat(root, "/hidden-compiled-", tags[si]);
let hiddencompileav: []str = [driver(stages[si]), "test", "-c", "-o",
compiled,
hiddentest];
runcommand(root, strings.concat(prefix, "hidden-test-compile"),
hiddencompileav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(out.stdout.len == 0 && same(out.stderr, sourcediag)
&& !os.exists(compiled)
&& !os.exists(strings.concat(compiled, ".sepwork")));
append(hiddendiagnostics, strings.dup(out.stderr));
let assembly: str = strings.concat(root, "/hidden-assembly-", tags[si]);
let hiddenasmav: []str = [driver(stages[si]), "test", "-S", "-o",
assembly,
hiddentest];
runcommand(root, strings.concat(prefix, "hidden-test-assembly"),
hiddenasmav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(out.stdout.len == 0 && same(out.stderr, sourcediag)
&& !os.exists(assembly)
&& !os.exists(strings.concat(assembly, ".sepwork")));
append(hiddendiagnostics, strings.dup(out.stderr));
let dottestav: []str = [driver(stages[si]), "test", dottest];
runcommand(root, strings.concat(prefix, "dot-missing-test"), dottestav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(same(out.stdout, "FAIL\n") && same(out.stderr, sourcediag)
&& !has(out.stderr, "absent.pkg"));
append(hiddendiagnostics, strings.dup(out.stderr));
let visiblework: str = strings.concat(root, "/visible-work-", tags[si]);
let visibleout: str = strings.concat(root, "/visible-output-", tags[si]);
mkdirall(visiblework);
let visiblebuildav: []str = [driver(stages[si]), "build", "-w",
visiblework, "-o",
visibleout, visiblewrong];
runcommand(root, strings.concat(prefix, "visible-wrong-platform-build"),
visiblebuildav, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0
&& os.exists(visibleout));
let runav: []str = [visibleout];
runcommand(root, strings.concat(prefix, "visible-wrong-platform-run"),
runav, (10i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0);
let visiblebytes: str = strings.dup(readfile(visibleout));
let ai: i32 = 0;
if (si == 0) { visiblebuildbin = strings.dup(visiblebytes); } else {
assert(same(visiblebuildbin, visiblebytes));
};
for (ai < rootartifacts.len) {
let bytes: str = strings.dup(readfile(strings.concat(visiblework,
rootartifacts[ai])));
if (si == 0) { append(visiblebuildartifacts, bytes); }
else { assert(same(visiblebuildartifacts[ai], bytes)); };
ai += 1;
};
let testwork: str = strings.concat(root, "/visible-test-work-", tags[si]);
mkdirall(testwork);
let visibletestav: []str = [driver(stages[si]), "test", "-w", testwork,
visiblewrongtest];
runcommand(root, strings.concat(prefix, "visible-wrong-platform-test"),
visibletestav, (60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stderr.len == 0
&& occurrences(out.stdout, "selected ... ok\n") == 1
&& occurrences(out.stdout,
"1 passed, 0 failed, 0 skipped, 0 harness errors\n") == 1);
let testbytes: str = strings.dup(readfile(strings.concat(testwork,
"/main")));
if (si == 0) {
visibletestbin = strings.dup(testbytes);
visibleteststdout = strings.dup(out.stdout);
} else {
assert(same(visibletestbin, testbytes)
&& same(visibleteststdout, out.stdout));
};
ai = 0;
for (ai < rootartifacts.len) {
let bytes: str = strings.dup(readfile(strings.concat(testwork,
rootartifacts[ai])));
if (si == 0) { append(visibletestartifacts, bytes); }
else { assert(same(visibletestartifacts[ai], bytes)); };
ai += 1;
};
let parentout: str = strings.concat(root, "/hidden-parent-", tags[si]);
let parentwork: str = strings.concat(root, "/hidden-parent-work-",
tags[si]);
mkdirall(parentwork);
let parentav: []str = [driver(stages[si]), "build", "-w", parentwork,
"-o", parentout, hiddenparentmain];
runcommand(root, strings.concat(prefix, "hidden-parent-visible-base"),
parentav, (30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0
&& same(visiblebuildbin, readfile(parentout)));
let hiddenlinkout: str = strings.concat(root, "/hidden-link-", tags[si]);
let hiddenlinkav: []str = [driver(stages[si]), "build", "-o",
hiddenlinkout, hiddenlink];
runcommand(root, strings.concat(prefix, "hidden-request-symlink"),
hiddenlinkav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
let symlinkdiag: str = strings.concat("ww: ", symlinks,
": directory contains no WW package sources\n");
assert(out.stdout.len == 0 && same(out.stderr, symlinkdiag)
&& !os.exists(hiddenlinkout)
&& !os.exists(strings.concat(hiddenlinkout, ".sepwork")));
append(hiddendiagnostics, strings.dup(out.stderr));
let deviceout: str = strings.concat(root, "/hidden-device-", tags[si]);
let devicework: str = strings.concat(root, "/hidden-device-work-",
tags[si]);
let deviceav: []str = [driver(stages[si]), "build", "-w", devicework,
"-o", deviceout, hiddendevice];
runcommand(root, strings.concat(prefix, "hidden-device-build"), deviceav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(out.stdout.len == 0 && same(out.stderr, symlinkdiag)
&& !os.exists(devicework) && !os.exists(deviceout)
&& !os.exists(strings.concat(deviceout, ".sepwork")));
append(hiddendiagnostics, strings.dup(out.stderr));
let devicetestwork: str = strings.concat(root,
"/hidden-device-test-work-", tags[si]);
let devicetestout: str = strings.concat(root,
"/hidden-device-test-output-", tags[si]);
let devicetestav: []str = [driver(stages[si]), "test", "-w",
devicetestwork, "-o", devicetestout, hiddendevice, "selected"];
runcommand(root, strings.concat(prefix, "hidden-device-test"),
devicetestav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
assert(same(out.stdout, "FAIL\n") && same(out.stderr, symlinkdiag)
&& !os.exists(devicetestwork) && !os.exists(devicetestout)
&& !os.exists(strings.concat(devicetestout, ".sepwork")));
append(hiddendiagnostics, strings.dup(out.stderr));
let visiblelinkout: str = strings.concat(root, "/visible-link-", tags[si]);
let visiblelinkwork: str = strings.concat(root, "/visible-link-work-",
tags[si]);
mkdirall(visiblelinkwork);
let visiblelinkav: []str = [driver(stages[si]), "build", "-w",
visiblelinkwork, "-o", visiblelinkout, visiblelink];
runcommand(root, strings.concat(prefix, "visible-request-symlink"),
visiblelinkav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0
&& same(visiblebuildbin, readfile(visiblelinkout)));
let warmwork: str = strings.concat(root, "/warm-work-", tags[si]);
let warmout: str = strings.concat(root, "/warm-output-", tags[si]);
mkdirall(warmwork);
let warmvalidav: []str = [driver(stages[si]), "build", "-w",
warmwork, "-o",
warmout, warmvisible];
runcommand(root, strings.concat(prefix, "warm-visible"), warmvalidav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0
&& os.exists(warmout));
let warmbin: str = strings.dup(readfile(warmout));
let warmsnapshots: []str = alloc([], rootartifacts.len: u64)!;
ai = 0;
for (ai < rootartifacts.len) {
append(warmsnapshots, strings.dup(readfile(strings.concat(warmwork,
rootartifacts[ai]))));
ai += 1;
};
assert(os.rename(warmvisible, warmhidden) == 0);
let warmhiddenav: []str = [driver(stages[si]), "build", "-w",
warmwork, "-o",
warmout, warmhidden];
runcommand(root, strings.concat(prefix, "warm-hidden"), warmhiddenav,
(30i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 1);
let warmdiag: str = strings.concat("ww: ", warm,
": directory contains no WW package sources\n");
assert(out.stdout.len == 0 && same(out.stderr, warmdiag)
&& same(warmbin, readfile(warmout))
&& !os.exists(strings.concat(warmout, ".new"))
&& !os.exists(strings.concat(warmout, ".sepwork")));
append(hiddendiagnostics, strings.dup(out.stderr));
ai = 0;
for (ai < rootartifacts.len) {
assert(same(warmsnapshots[ai], readfile(strings.concat(warmwork,
rootartifacts[ai]))));
ai += 1;
};
assert(!directoryhasnew(warmwork)
&& !directoryhasfragment(warmwork, ".wwtxn.")
&& !directoryhasfragment(warmwork, ".install")
&& !directoryhasfragment(warmwork, ".sepwork"));
assert(os.rename(warmhidden, warmvisible) == 0);
runcommand(root, strings.concat(prefix, "warm-restored"), warmvalidav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(out.stdout.len == 0 && out.stderr.len == 0
&& same(warmbin, readfile(warmout)));
ai = 0;
for (ai < rootartifacts.len) {
assert(same(warmsnapshots[ai], readfile(strings.concat(warmwork,
rootartifacts[ai]))));
ai += 1;
};
assert(!directoryhasnew(warmwork)
&& !directoryhasfragment(warmwork, ".wwtxn.")
&& !directoryhasfragment(warmwork, ".install")
&& !directoryhasfragment(warmwork, ".sepwork"));
si += 1;
};
let half: i32 = hiddendiagnostics.len / 2;
let di: i32 = 0;
for (di < half) {
assert(same(hiddendiagnostics[di], hiddendiagnostics[di + half]));
di += 1;
};
assert(!directoryhasnew(root)
&& !directoryhasfragment(root, ".wwtxn.")
&& !directoryhasfragment(root, ".install")
&& !directoryhasfragment(root, ".sepwork")
&& !directoryhasfragment(root, ".capture")
&& !directoryhasfragment(root, ".result")
&& !directoryhasfragment(root, ".request"));
clean(root);
};
// A source file has one contiguous import section immediately after its
// package clause. The parser may continue after a late import for recovery,
// but the imports-only loader and the full compiler parser both reject it.