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'; 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 /* Go's build -o directory branch follows an existing destination through
* stat, and a trailing platform separator declares a directory which the * stat, and a trailing platform separator declares a directory which the
* request may need to create. WW's platform separator is '/'. */ * request may need to create. WW's platform separator is '/'. */
@@ -7442,6 +7474,11 @@ do_build(int argc, char **argv)
} }
struct stat requested; struct stat requested;
int literal = stat(src, &requested) == 0; int literal = stat(src, &requested) == 0;
if (source_operand_ignored(src)) {
source_operand_no_sources(src);
free(incs);
return 1;
}
char resolved[PATH_MAX]; char resolved[PATH_MAX];
int is_dir = 0; int is_dir = 0;
if (!resolve_module(src, incs, resolved, sizeof resolved, &is_dir)) { 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; 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) { if (pattern != NULL) {
struct stat first; struct stat first;
if (stat(target, &first) != 0 || !S_ISREG(first.st_mode)) { 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 Build workdir format remains `18`, test workdir format remains `19`, semantic
storage format remains `3`, and no test-result cache is introduced. 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 ## 12. Candidate architectures and hard-gate decision
Five candidates were developed as coherent systems, not as feature bins. 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 delegated graph-import scan or tools. An ordinary build compares production
names only; one test product compares its production, same-package test, and names only; one test product compares its production, same-package test, and
external-test selections without merging their units. 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 - `import acme.codec;` loads the canonical package `acme.codec`. If that
package declares `package wire;`, the importing file sees its exported names package declares `package wire;`, the importing file sees its exported names
as `wire.Name`; `codec.Name` is not an additional binding. An explicit alias 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: run loop exactly. Measured on the 31-package `lib/...` walk:
7.0s sequential, 2.4s at `-j 4`. 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 List mode uses that same product process and initialization boundary but starts
no per-test child. The shared language harness emits only selected qualified 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 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; 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 = { fn arenadupcstr(src: *u8, plen: u64) *u8 = {
let buf: []u8 = alloc([], plen + 1u64)!; let buf: []u8 = alloc([], plen + 1u64)!;
let i: u64 = 0u64; let i: u64 = 0u64;
@@ -8914,6 +8948,10 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
case void => requestedliteral = true; case void => requestedliteral = true;
case let e: os.oserror => void; case let e: os.oserror => void;
}; };
if (sourceoperandignored(src)) {
sourceoperandnosources(src);
return 1;
};
let isdir: i32 = 0; let isdir: i32 = 0;
let resolved: *u8 = resolvemodule(selfdir, src, incs.ptr, &isdir); let resolved: *u8 = resolvemodule(selfdir, src, incs.ptr, &isdir);
if (resolved == nil) { if (resolved == nil) {
@@ -9792,6 +9830,26 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
producti += 1; 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) { if (patarg != nil) {
let first: os.filestat; let first: os.filestat;
let firstregular: bool = false; let firstregular: bool = false;

View File

@@ -987,6 +987,354 @@ fn cwdwritedata(dir: str, label: str) void = {
clean(root); 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 // A source file has one contiguous import section immediately after its
// package clause. The parser may continue after a late import for recovery, // 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. // but the imports-only loader and the full compiler parser both reject it.