run: reject .ww directories as named sources
This commit is contained in:
@@ -7706,6 +7706,19 @@ do_run(int argc, char **argv)
|
|||||||
if (src == NULL) src = ".";
|
if (src == NULL) src = ".";
|
||||||
struct stat requested;
|
struct stat requested;
|
||||||
int literal = stat(src, &requested) == 0;
|
int literal = stat(src, &requested) == 0;
|
||||||
|
if (literal && S_ISDIR(requested.st_mode)) {
|
||||||
|
size_t n = strlen(src);
|
||||||
|
if (n >= 3 && strcmp(src + n - 3, ".ww") == 0) {
|
||||||
|
if (n >= 8 && strcmp(src + n - 8, "_test.ww") == 0)
|
||||||
|
fprintf(stderr,
|
||||||
|
"ww: cannot run *_test.ww files (%s)\n", src);
|
||||||
|
else
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s is a directory, should be a WW file\n", 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)) {
|
||||||
|
|||||||
@@ -10376,6 +10376,141 @@ test/run command boundaries. No serialized representation changes: build
|
|||||||
workdir format remains `18`, test workdir format remains `19`, semantic storage
|
workdir format remains `18`, test workdir format remains `19`, semantic storage
|
||||||
format remains `3`, and no cache or result record is added.
|
format remains `3`, and no cache or result record is added.
|
||||||
|
|
||||||
|
### 11.53 Implemented `.ww`-spelled directory run rejection
|
||||||
|
|
||||||
|
An existing target selected by `ww run` whose exact requested spelling ends
|
||||||
|
`.ww` is a named-source request when ordinary symlink-following `stat` reports
|
||||||
|
a directory. Run rejects that directory before package resolution or private
|
||||||
|
work creation. This is deliberately different from section 11.52's build/test
|
||||||
|
directory route: the command-specific front door, not the shared resolver,
|
||||||
|
owns the distinction.
|
||||||
|
|
||||||
|
#### Pinned authority and applicability
|
||||||
|
|
||||||
|
- **behavior directly implemented or asserted by pinned Go** — official Go
|
||||||
|
1.26.5 commit `c19862e5f8415b4f24b189d065ed739517c548ba`
|
||||||
|
scans leading `.go` operands at
|
||||||
|
`cmd/go/internal/run/run.go:73–112`, rejecting an `_test.go` spelling at
|
||||||
|
103–109 before passing the named set to `GoFilesPackage`.
|
||||||
|
`cmd/go/internal/load/pkg.go:3244–3289`, especially 3274–3281, follows
|
||||||
|
`Stat` and fatals when a named operand is a directory. Later checking,
|
||||||
|
action construction, linking, and execution at `run.go:141–173` are not
|
||||||
|
reached.
|
||||||
|
- **behavior directly implemented or asserted by pinned Go** — the exact Go
|
||||||
|
status, header-free diagnostic, and terminating newline follow
|
||||||
|
`cmd/go/internal/base/base.go:137–145,175–183`,
|
||||||
|
`cmd/go/main.go:98–100`, and `log/log.go:200–245`. Official
|
||||||
|
`cmd/go/testdata/script/run_hello.txt:1–10`, `run_dirs.txt:1–20`, and
|
||||||
|
`run_set_executable_name.txt:4–17` anchor the named-file run front and its
|
||||||
|
distinction from package-form run. Indirect official directory-kind anchors
|
||||||
|
are `list_ambiguous_path.txt:4–15,29–36`,
|
||||||
|
`mod_get_go_file.txt:47–58`, and `mod_symlink_dotgo.txt:4–9`. No official
|
||||||
|
end-to-end `go run` test asserts this directory diagnostic; the result is
|
||||||
|
implemented directly by the cited source.
|
||||||
|
- **behavior derived from the pinned implementation** — WW's `.ww`
|
||||||
|
named-source spelling and existing directory-package form meet at the same
|
||||||
|
practical boundary. The applicable adaptation uses `WW file` and
|
||||||
|
`*_test.ww` while preserving requested operand bytes. It requires no module,
|
||||||
|
manifest, registry, network lookup, generalized import grammar, cache,
|
||||||
|
database, CAS, or build expression.
|
||||||
|
|
||||||
|
#### Ownership, selection, and diagnostics
|
||||||
|
|
||||||
|
- **directly measured WW behavior** — before this change, Cstage followed a
|
||||||
|
direct `.ww` directory or visible `.ww`/`_test.ww` symlink into the ordinary
|
||||||
|
directory graph, invoked compiler, assemblers, linker, and user program, and
|
||||||
|
returned that program's status. WWstage instead entered raw-source loading,
|
||||||
|
returned status 1 with exact `ww: cannot read source\n`, and ran no producer
|
||||||
|
or program. Both removed the private work they had unnecessarily created.
|
||||||
|
- **behavior derived from the pinned implementation** — the true WW owners
|
||||||
|
are only `cmd/ww/main.c::do_run` and
|
||||||
|
`selfhost/cmd/ww/main.ww::dorun`, after their existing option/target parse
|
||||||
|
and requested `stat`, but before `resolve_module`/`resolvemodule` and run
|
||||||
|
scratch creation. Changing the shared resolver would wrongly change the
|
||||||
|
distinct build, test, logical, and dotted-package fronts.
|
||||||
|
- **directly measured WW behavior** — after the run-local classification,
|
||||||
|
both stages return status 1 with empty stdout. A requested spelling ending
|
||||||
|
`_test.ww` emits exactly
|
||||||
|
`ww: cannot run *_test.ww files (OPERAND)\n`; every other selected directory
|
||||||
|
ending `.ww` emits exactly
|
||||||
|
`OPERAND is a directory, should be a WW file\n`. The requested operand is
|
||||||
|
reproduced unchanged. `_test.ww` precedence applies before ordinary
|
||||||
|
directory rejection, including through a symlink.
|
||||||
|
- **directly measured WW behavior** — the rule includes direct and symlinked
|
||||||
|
`.ww` directories and hidden directory spellings `.hidden.ww` and
|
||||||
|
`_hidden.ww`. It also precedes malformed package clauses and missing imports
|
||||||
|
inside the directory because no member is selected or opened. Existing run
|
||||||
|
option errors and target determination retain their earlier precedence.
|
||||||
|
A trailing separator does not end `.ww`; non-`.ww` directories and dotted
|
||||||
|
logical requests retain the established package route.
|
||||||
|
|
||||||
|
#### Build, test, package, and import effects
|
||||||
|
|
||||||
|
- **directly measured WW behavior** — package/source selection is the primary
|
||||||
|
axis. The rejected request creates no raw or directory package, canonical
|
||||||
|
identity, declared-name instance, test variant, initializer, graph node, or
|
||||||
|
action. Requested spelling and followed target are diagnostic observations
|
||||||
|
only, never canonical package, action, symbol, artifact, `.wwi`,
|
||||||
|
publication, or persistence identity.
|
||||||
|
- **directly measured WW behavior** — build retains section 11.52's stat-first
|
||||||
|
rule for the same direct and symlink spellings. It still enumerates the
|
||||||
|
directory, discovers its dotted dependencies, constructs ordinary package
|
||||||
|
actions, and applies the established default, explicit, directory,
|
||||||
|
`/dev/null`, `-S`, publication, persistence, invalidation, and rollback
|
||||||
|
policies. Unaffected build controls retain stage-byte-identical public and
|
||||||
|
semantic artifacts.
|
||||||
|
- **directly measured WW behavior** — raw `ww test`, `ww test -c`, and
|
||||||
|
directory `ww test -S` retain their stat-first directory selection and
|
||||||
|
established diagnostics/artifact bytes. Test package variants, generated
|
||||||
|
main, process topology, filtering, capture, result ordering, retention, and
|
||||||
|
result non-caching are unchanged.
|
||||||
|
- **directly measured WW behavior** — imports are not scanned on the selected
|
||||||
|
run rejection and create no qualifier or edge. Dotted and non-`.ww` package
|
||||||
|
controls retain exact canonical import identity, dependency discovery, and
|
||||||
|
runtime behavior. No physical directory becomes canonical identity through
|
||||||
|
this rule.
|
||||||
|
|
||||||
|
#### Actions, lifecycle, parity, and scope
|
||||||
|
|
||||||
|
- **directly measured WW behavior** — selected rejection invokes no compiler,
|
||||||
|
assembler, archiver, linker, initializer, runtime, or owned child/process
|
||||||
|
group. A fixture-preoccupied exact `/tmp/ww_run_<pid>` plus sentinel remains
|
||||||
|
untouched, proving that the driver does not acquire or mutate its run-scratch
|
||||||
|
path; final cleanup leaves that path absent. It also creates no output,
|
||||||
|
`.sepwork`, unit, `.wwi`, assembly, object, archive, executable, capture,
|
||||||
|
result, transaction, stage, backup, or persistent record. Thus
|
||||||
|
producer/runtime failure, publication, reuse, invalidation, and rollback are
|
||||||
|
inapplicable on this preflight route; all prior caller and committed bytes
|
||||||
|
remain untouched.
|
||||||
|
- **directly measured WW behavior** — classification is request-local,
|
||||||
|
read-only, and isolated under concurrency. An interruption in this preflight
|
||||||
|
owns no child or filesystem resource. The general direct-driver interruption
|
||||||
|
gap from section 11.52 remains open: a different request interrupted after
|
||||||
|
transaction staging can still leave fixed-name `.new` files and poison
|
||||||
|
later persistent reuse. This slice neither reaches nor fixes that machinery.
|
||||||
|
- **directly measured WW behavior** — Cstage and WWstage match exactly on
|
||||||
|
status, stdout, stderr, diagnostic bytes, empty producer traces, artifact
|
||||||
|
absence, exact PID-path non-acquisition and final absence, concurrent
|
||||||
|
isolation, and cleanup for every selected row. Unaffected controls retain
|
||||||
|
diagnostic and public or semantic artifact-byte parity.
|
||||||
|
- **behavior derived from the pinned implementation** — this narrow
|
||||||
|
file-kind slice does not implement the complete suffix-first run front.
|
||||||
|
Regular or missing `_test.ww`, missing or logical `.ww`, multiple named
|
||||||
|
sources, finite FIFOs, and hidden regular sources retain their prior routes
|
||||||
|
and remain separately open where different. Recursive requests, ordinary
|
||||||
|
directory requests, and generalized imports are not changed.
|
||||||
|
|
||||||
|
The focused WW-native observer covers direct, symlinked, hidden, ordinary, and
|
||||||
|
`_test.ww` directory spellings; malformed-package and missing-import
|
||||||
|
precedence; exact requested diagnostics; empty tool/runtime traces; exact
|
||||||
|
PID-path non-acquisition and final absence; concurrency and cleanup;
|
||||||
|
trailing-separator,
|
||||||
|
non-`.ww`, regular-source, and dotted logical run controls; and unchanged
|
||||||
|
same-spelling build and raw/compile-only/assembly-only test boundaries. No
|
||||||
|
serialized representation changes: build workdir format remains `18`, test
|
||||||
|
workdir format remains `19`, semantic storage format remains `3`, and no cache
|
||||||
|
or result record is added.
|
||||||
|
|
||||||
## 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.
|
||||||
|
|||||||
29
docs/spec.md
29
docs/spec.md
@@ -370,10 +370,31 @@ ImportPath = ident { "." ident } .
|
|||||||
no new package, dotted-import, graph, action, symbol, artifact, `.wwi`,
|
no new package, dotted-import, graph, action, symbol, artifact, `.wwi`,
|
||||||
publication, or persistence identity. Raw `ww test`, `ww test -c`, and
|
publication, or persistence identity. Raw `ww test`, `ww test -c`, and
|
||||||
`ww test -S` already use the same directory classification and are unchanged.
|
`ww test -S` already use the same directory classification and are unchanged.
|
||||||
`ww run` retains its separate named-operand front door. Multiple operands,
|
`ww run` retains its separate named-operand front door, with its
|
||||||
recursive and logical requests, regular and non-regular source targets, and
|
`.ww`-spelled directory rule specified next. Multiple operands, recursive
|
||||||
dangling symlinks are not changed. Build workdir format remains 18, test
|
and logical requests, regular and non-regular source targets, and dangling
|
||||||
workdir format remains 19, and semantic storage format remains 3.
|
symlinks are not changed. Build workdir format remains 18, test workdir
|
||||||
|
format remains 19, and semantic storage format remains 3.
|
||||||
|
- For `ww run`, an existing selected target whose exact requested spelling
|
||||||
|
ends `.ww` is a named-source request when symlink-following `stat` reports a
|
||||||
|
directory. The command rejects it before shared resolution, directory
|
||||||
|
enumeration, source/import loading, graph/action construction, private run
|
||||||
|
scratch, producers, or runtime. A requested suffix `_test.ww` has the earlier
|
||||||
|
exact diagnostic
|
||||||
|
`ww: cannot run *_test.ww files (OPERAND)\n`; every other such directory has
|
||||||
|
exact diagnostic `OPERAND is a directory, should be a WW file\n`. Both forms
|
||||||
|
return status 1 with empty stdout and reproduce the requested operand bytes
|
||||||
|
unchanged. The rule follows a terminal symlink, includes `.hidden.ww` and
|
||||||
|
`_hidden.ww` directory spellings, and precedes any malformed package or
|
||||||
|
missing import inside the directory. A trailing separator does not end
|
||||||
|
`.ww`; ordinary non-`.ww` directories, dotted logical requests, regular and
|
||||||
|
missing operands, multiple named operands, and non-directory non-regular
|
||||||
|
targets retain their established routes. The rejected spelling and followed
|
||||||
|
target are diagnostic metadata only and create no package/import identity,
|
||||||
|
graph/action, symbol, artifact, `.wwi`, publication, transaction,
|
||||||
|
persistence, process, or filesystem owner. Build and all test forms retain
|
||||||
|
their distinct stat-first directory behavior. Build workdir format remains
|
||||||
|
18, test workdir format remains 19, and semantic storage format remains 3.
|
||||||
- `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
|
||||||
|
|||||||
@@ -278,12 +278,29 @@ parity, direct and symlinked `.ww` directories, a dotted dependency, output
|
|||||||
modes, cold/warm transaction behavior, compiler and signaled-linker failure
|
modes, cold/warm transaction behavior, compiler and signaled-linker failure
|
||||||
preservation, selected-route concurrency, cleanup, and the exact test-command
|
preservation, selected-route concurrency, cleanup, and the exact test-command
|
||||||
behavior. Direct driver interruption remains owned by the unchanged directory
|
behavior. Direct driver interruption remains owned by the unchanged directory
|
||||||
machinery and is not claimed fixed here. The shared resolver and `ww run` are
|
machinery and is not claimed fixed here.
|
||||||
deliberately unchanged—and the observer
|
|
||||||
retains their pre-existing stage difference—because pinned Go's run command
|
Pinned Go's run command has a distinct suffix-first named-file front door.
|
||||||
has a distinct named-file front door.
|
Accordingly, an existing `ww run` target whose exact requested spelling ends
|
||||||
No test product, result, package/import identity, or serialized format changes;
|
`.ww` and whose symlink-following `stat` result is a directory is rejected in
|
||||||
build remains 18, test remains 19, and semantic storage remains 3.
|
the twin run fronts before the shared resolver and private run scratch. An
|
||||||
|
`_test.ww` spelling emits exactly
|
||||||
|
`ww: cannot run *_test.ww files (OPERAND)\n`; every other selected `.ww`
|
||||||
|
directory emits exactly `OPERAND is a directory, should be a WW file\n`.
|
||||||
|
Both stages return status 1 with empty stdout, open no directory member, scan
|
||||||
|
no import, construct no package/graph/action, invoke no producer or runtime,
|
||||||
|
and create no run scratch or artifact. This includes direct and symlinked
|
||||||
|
directories and hidden directory spellings; directory contents cannot displace
|
||||||
|
the classifier diagnostic. A trailing separator and non-`.ww` or dotted
|
||||||
|
package requests retain the directory package route. The same-spelling build,
|
||||||
|
raw test, `test -c`, and directory `test -S` routes remain stat-first and keep
|
||||||
|
their existing diagnostics and artifact bytes. Thus this run change creates no
|
||||||
|
test product, result, package/import identity, test-process/filter change, or
|
||||||
|
serialized-format change; build remains 18, test remains 19, and semantic
|
||||||
|
storage remains 3. Regular or missing `_test.ww`, missing/logical `.ww`,
|
||||||
|
multiple named sources, finite FIFOs, and hidden regular sources are not
|
||||||
|
claimed by this existing-directory slice. The general direct-driver `.new`
|
||||||
|
interruption residue also remains open.
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
@@ -9321,6 +9321,16 @@ fn dorun(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 (requestedliteral
|
||||||
|
&& ((requestedstat.mode: u32) & 61440u32) == os.mode.DIR: u32
|
||||||
|
&& cstrendswithlit(src, ".ww")) {
|
||||||
|
if (cstrendswithlit(src, "_test.ww")) {
|
||||||
|
cerrpath("ww: cannot run *_test.ww files (", src, ")\n");
|
||||||
|
} else {
|
||||||
|
cerrpath("", src, " is a directory, should be a WW file\n");
|
||||||
|
};
|
||||||
|
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) {
|
||||||
|
|||||||
@@ -1466,8 +1466,8 @@ fn cwdwritedata(dir: str, label: str) void = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// A visible raw test-source build observes only its initial package/import
|
// A visible raw test-source build observes only its initial package/import
|
||||||
// header and then omits it. A .ww-spelled directory, including a symlink with
|
// header and then omits it. Build and test retain their directory-package
|
||||||
// a _test.ww spelling, instead enters the ordinary directory-package route.
|
// front door, while run's named-source front rejects a .ww-spelled directory.
|
||||||
// Neither classification may redefine package or dotted-import identity.
|
// Neither classification may redefine package or dotted-import identity.
|
||||||
@test fn named_test_sources_are_header_loaded_then_omitted() void = {
|
@test fn named_test_sources_are_header_loaded_then_omitted() void = {
|
||||||
let root: str = fresh();
|
let root: str = fresh();
|
||||||
@@ -1593,6 +1593,8 @@ fn cwdwritedata(dir: str, label: str) void = {
|
|||||||
let linkersignaldiag: str = "";
|
let linkersignaldiag: str = "";
|
||||||
let directorytestrunout: str = "";
|
let directorytestrunout: str = "";
|
||||||
let directorytestrunerr: str = "";
|
let directorytestrunerr: str = "";
|
||||||
|
let directoryrunout: str = "";
|
||||||
|
let directoryrunerr: str = "";
|
||||||
let directorytestrunartifacts: str = "";
|
let directorytestrunartifacts: str = "";
|
||||||
let directorytestbin: str = "";
|
let directorytestbin: str = "";
|
||||||
let directorytestcompileartifacts: str = "";
|
let directorytestcompileartifacts: str = "";
|
||||||
@@ -2202,21 +2204,25 @@ fn cwdwritedata(dir: str, label: str) void = {
|
|||||||
if (si == 0) { directorytestasm = strings.dup(out.stderr); }
|
if (si == 0) { directorytestasm = strings.dup(out.stderr); }
|
||||||
else { assert(same(directorytestasm, out.stderr)); };
|
else { assert(same(directorytestasm, out.stderr)); };
|
||||||
|
|
||||||
// Run was not changed by the build-only dispatcher fix. Cstage follows
|
// Run's named-source front rejects the requested _test.ww spelling
|
||||||
// the selected directory and executes it; WWstage retains its exact
|
// before directory loading, tool production, or runtime execution.
|
||||||
// pre-existing raw-source failure for the same requested symlink.
|
|
||||||
let directoryrunav: []str = [driver(stages[si]), "run", "-I", include,
|
let directoryrunav: []str = [driver(stages[si]), "run", "-I", include,
|
||||||
dirlink];
|
dirlink];
|
||||||
runcommandenv(root, strings.concat("testonly-directory-run-", tags[si]),
|
runcommandenv(root, strings.concat("testonly-directory-run-", tags[si]),
|
||||||
directoryrunav, env,
|
directoryrunav, env,
|
||||||
(60i64 * (time.second: i64)): time.duration, &out);
|
(60i64 * (time.second: i64)): time.duration, &out);
|
||||||
if (si == 0) {
|
let directoryrundiag: str = strings.concat(
|
||||||
expectexit(&out, 5);
|
"ww: cannot run *_test.ww files (", dirlink, ")\n");
|
||||||
assert(out.stdout.len == 0 && out.stderr.len == 0);
|
|
||||||
} else {
|
|
||||||
expectexit(&out, 1);
|
expectexit(&out, 1);
|
||||||
assert(out.stdout.len == 0
|
assert(out.stdout.len == 0 && same(out.stderr, directoryrundiag)
|
||||||
&& same(out.stderr, "ww: cannot read source\n"));
|
&& readfile(ctrace).len == 0 && readfile(atrace).len == 0
|
||||||
|
&& readfile(ltrace).len == 0);
|
||||||
|
if (si == 0) {
|
||||||
|
directoryrunout = strings.dup(out.stdout);
|
||||||
|
directoryrunerr = strings.dup(out.stderr);
|
||||||
|
} else {
|
||||||
|
assert(same(directoryrunout, out.stdout)
|
||||||
|
&& same(directoryrunerr, out.stderr));
|
||||||
};
|
};
|
||||||
rewritefile(dirtargettest, dirtargettestexcluded);
|
rewritefile(dirtargettest, dirtargettestexcluded);
|
||||||
|
|
||||||
@@ -2420,6 +2426,396 @@ fn cwdwritedata(dir: str, label: str) void = {
|
|||||||
clean(root);
|
clean(root);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn expectrundirectoryrejection(root: str, name: str, av: []str, env: []str,
|
||||||
|
pidrecord: str, ctrace: str, atrace: str, ltrace: str, want: str) void = {
|
||||||
|
rewritefile(pidrecord, "");
|
||||||
|
rewritefile(ctrace, "");
|
||||||
|
rewritefile(atrace, "");
|
||||||
|
rewritefile(ltrace, "");
|
||||||
|
let out: commandout;
|
||||||
|
runcommandenv(root, name, av, env,
|
||||||
|
(60i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
let ownedrun: str = readfile(pidrecord);
|
||||||
|
let ownedmarker: str = strings.concat(ownedrun, "/observer-marker");
|
||||||
|
let ownedvalid: bool = ownedrun.len > 12
|
||||||
|
&& strings.hasprefix(ownedrun, "/tmp/ww_run_");
|
||||||
|
let observed: bool = out.termination == exec.termination.EXIT
|
||||||
|
&& out.code == 1 && out.stdout.len == 0 && same(out.stderr, want)
|
||||||
|
&& ownedvalid && os.exists(ownedrun)
|
||||||
|
&& same(readfile(ownedmarker), "observer-owned\n")
|
||||||
|
&& readfile(ctrace).len == 0 && readfile(atrace).len == 0
|
||||||
|
&& readfile(ltrace).len == 0;
|
||||||
|
let markerclean: i32 = -1;
|
||||||
|
let dirclean: i32 = -1;
|
||||||
|
if (ownedvalid) {
|
||||||
|
markerclean = os.remove(ownedmarker);
|
||||||
|
dirclean = os.rmdir(ownedrun);
|
||||||
|
};
|
||||||
|
assert(observed && markerclean == 0 && dirclean == 0
|
||||||
|
&& !os.exists(ownedrun));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Run's named-source spelling owns the directory rejection. The physical
|
||||||
|
// directory remains only loader metadata for the distinct build and test
|
||||||
|
// fronts, and rejected source contents cannot create package or import state.
|
||||||
|
@test fn run_dot_ww_directories_are_named_sources() void = {
|
||||||
|
let root: str = fresh();
|
||||||
|
let source: str = strings.concat(root, "/source");
|
||||||
|
let include: str = strings.concat(root, "/include");
|
||||||
|
let dependency: str = strings.concat(include, "/domain/value");
|
||||||
|
let logical: str = strings.concat(include, "/domain/logical");
|
||||||
|
let ordinary: str = strings.concat(source, "/ordinary.ww");
|
||||||
|
let ordinarylink: str = strings.concat(source, "/requested.ww");
|
||||||
|
let testdirectory: str = strings.concat(source, "/direct_test.ww");
|
||||||
|
let testlink: str = strings.concat(source, "/requested_test.ww");
|
||||||
|
let hidden: str = strings.concat(source, "/.hidden.ww");
|
||||||
|
let private: str = strings.concat(source, "/_hidden.ww");
|
||||||
|
let malformed: str = strings.concat(source, "/malformed.ww");
|
||||||
|
let missingimport: str = strings.concat(source, "/missing-import.ww");
|
||||||
|
let nonsuffix: str = strings.concat(source, "/directory-control");
|
||||||
|
let nonsuffixlink: str = strings.concat(source, "/directory-link");
|
||||||
|
let regular: str = strings.concat(source, "/regular.ww");
|
||||||
|
let rawtest: str = strings.concat(source, "/raw_control_test.ww");
|
||||||
|
let prior: str = strings.concat(root, "/prior-public-output");
|
||||||
|
mkdirall(dependency); mkdirall(logical); mkdirall(ordinary);
|
||||||
|
mkdirall(testdirectory); mkdirall(hidden); mkdirall(private);
|
||||||
|
mkdirall(malformed); mkdirall(missingimport); mkdirall(nonsuffix);
|
||||||
|
writefile(strings.concat(dependency, "/value.ww"), strings.concat(
|
||||||
|
"package value;\n",
|
||||||
|
"export fn number() i32 = { return 37; };\n"));
|
||||||
|
writefile(strings.concat(ordinary, "/main.ww"), strings.concat(
|
||||||
|
"package main;\nimport domain.value;\n",
|
||||||
|
"fn main() i32 = { return value.number(); };\n"));
|
||||||
|
writefile(strings.concat(testdirectory, "/main.ww"),
|
||||||
|
"package main;\nfn main() i32 = { return 47; };\n");
|
||||||
|
writefile(strings.concat(hidden, "/main.ww"),
|
||||||
|
"package main;\nfn main() i32 = { return 48; };\n");
|
||||||
|
writefile(strings.concat(private, "/main.ww"),
|
||||||
|
"package main;\nfn main() i32 = { return 49; };\n");
|
||||||
|
writefile(strings.concat(malformed, "/main.ww"),
|
||||||
|
"this directory has no package clause\n");
|
||||||
|
writefile(strings.concat(missingimport, "/main.ww"), strings.concat(
|
||||||
|
"package main;\nimport absent.before.run.classification;\n",
|
||||||
|
"fn main() i32 = { return 50; };\n"));
|
||||||
|
writefile(strings.concat(nonsuffix, "/main.ww"),
|
||||||
|
"package main;\nfn main() i32 = { return 43; };\n");
|
||||||
|
writefile(regular,
|
||||||
|
"package main;\nfn main() i32 = { return 39; };\n");
|
||||||
|
writefile(strings.concat(logical, "/main.ww"),
|
||||||
|
"package main;\nfn main() i32 = { return 41; };\n");
|
||||||
|
writefile(rawtest, strings.concat(
|
||||||
|
"package runroute;\n",
|
||||||
|
"@test fn raw_control() void = { assert(true); };\n"));
|
||||||
|
writefile(prior, "prior-public-bytes\n");
|
||||||
|
assert(os.symlink(ordinary, ordinarylink) == 0);
|
||||||
|
assert(os.symlink(testdirectory, testlink) == 0);
|
||||||
|
assert(os.symlink(nonsuffix, nonsuffixlink) == 0);
|
||||||
|
|
||||||
|
let driverwrapper: str = strings.concat(root, "/driver-wrapper.sh");
|
||||||
|
let compilerwrapper: str = strings.concat(root, "/compiler-wrapper.sh");
|
||||||
|
let assemblerwrapper: str = strings.concat(root, "/assembler-wrapper.sh");
|
||||||
|
let linkerwrapper: str = strings.concat(root, "/linker-wrapper.sh");
|
||||||
|
writeexecutable(driverwrapper, strings.concat(
|
||||||
|
"#!/bin/sh\nowned=/tmp/ww_run_$$\n",
|
||||||
|
"printf '%s' \"$owned\" > \"$WW_RUN_PID_RECORD\"\n",
|
||||||
|
"if test \"$WW_RUN_PREOCCUPY\" = 1; then\n",
|
||||||
|
" mkdir \"$owned\" || exit 124\n",
|
||||||
|
" printf 'observer-owned\\n' > \"$owned/observer-marker\"\n",
|
||||||
|
"fi\n",
|
||||||
|
"exec \"$WW_RUN_REAL_DRIVER\" \"$@\"\n"));
|
||||||
|
writeexecutable(compilerwrapper, strings.concat(
|
||||||
|
"#!/bin/sh\nprintf 'compile\\n' >> \"$WW_RUN_CTRACE\"\n",
|
||||||
|
"exec \"$WW_RUN_REAL_C\" \"$@\"\n"));
|
||||||
|
writeexecutable(assemblerwrapper, strings.concat(
|
||||||
|
"#!/bin/sh\nprintf 'assemble\\n' >> \"$WW_RUN_ATRACE\"\n",
|
||||||
|
"exec \"$WW_RUN_REAL_A\" \"$@\"\n"));
|
||||||
|
writeexecutable(linkerwrapper, strings.concat(
|
||||||
|
"#!/bin/sh\nprintf 'link\\n' >> \"$WW_RUN_LTRACE\"\n",
|
||||||
|
"exec \"$WW_RUN_REAL_L\" \"$@\"\n"));
|
||||||
|
|
||||||
|
let stages: []str = ["ww", "ww_ww"];
|
||||||
|
let compilers: []str = ["w6c", "w6c_ww"];
|
||||||
|
let assemblers: []str = ["w6a", "w6a_ww"];
|
||||||
|
let linkers: []str = ["w6l", "w6l_ww"];
|
||||||
|
let tags: []str = ["c", "ww"];
|
||||||
|
let environments: [][]str = alloc([], 2u64)!;
|
||||||
|
let rejectenvironments: [][]str = alloc([], 2u64)!;
|
||||||
|
let pidrecords: []str = alloc([], 2u64)!;
|
||||||
|
let ctraces: []str = alloc([], 2u64)!;
|
||||||
|
let atraces: []str = alloc([], 2u64)!;
|
||||||
|
let ltraces: []str = alloc([], 2u64)!;
|
||||||
|
let inherited: []str = os.getenvs();
|
||||||
|
let si: i32 = 0;
|
||||||
|
for (si < stages.len) {
|
||||||
|
let pidrecord: str = strings.concat(root, "/driver-pid-", tags[si]);
|
||||||
|
let ctrace: str = strings.concat(root, "/compiler-trace-", tags[si]);
|
||||||
|
let atrace: str = strings.concat(root, "/assembler-trace-", tags[si]);
|
||||||
|
let ltrace: str = strings.concat(root, "/linker-trace-", tags[si]);
|
||||||
|
writefile(pidrecord, ""); writefile(ctrace, "");
|
||||||
|
writefile(atrace, ""); writefile(ltrace, "");
|
||||||
|
append(pidrecords, pidrecord); append(ctraces, ctrace);
|
||||||
|
append(atraces, atrace); append(ltraces, ltrace);
|
||||||
|
let env: []str = alloc([], (inherited.len + 11): u64)!;
|
||||||
|
let ei: i32 = 0;
|
||||||
|
for (ei < inherited.len) {
|
||||||
|
if (!strings.hasprefix(inherited[ei], "WW_W6C=")
|
||||||
|
&& !strings.hasprefix(inherited[ei], "WW_W6A=")
|
||||||
|
&& !strings.hasprefix(inherited[ei], "WW_W6L=")
|
||||||
|
&& !strings.hasprefix(inherited[ei], "WW_RUN_")) {
|
||||||
|
append(env, inherited[ei]);
|
||||||
|
};
|
||||||
|
ei += 1;
|
||||||
|
};
|
||||||
|
append(env, strings.concat("WW_RUN_REAL_DRIVER=", driver(stages[si])));
|
||||||
|
append(env, strings.concat("WW_RUN_PID_RECORD=", pidrecord));
|
||||||
|
append(env, strings.concat("WW_W6C=", compilerwrapper));
|
||||||
|
append(env, strings.concat("WW_W6A=", assemblerwrapper));
|
||||||
|
append(env, strings.concat("WW_W6L=", linkerwrapper));
|
||||||
|
append(env, strings.concat("WW_RUN_CTRACE=", ctrace));
|
||||||
|
append(env, strings.concat("WW_RUN_ATRACE=", atrace));
|
||||||
|
append(env, strings.concat("WW_RUN_LTRACE=", ltrace));
|
||||||
|
append(env, strings.concat("WW_RUN_REAL_C=", driver(compilers[si])));
|
||||||
|
append(env, strings.concat("WW_RUN_REAL_A=", driver(assemblers[si])));
|
||||||
|
append(env, strings.concat("WW_RUN_REAL_L=", driver(linkers[si])));
|
||||||
|
append(environments, env);
|
||||||
|
let rejectenv: []str = alloc([], (env.len + 1): u64)!;
|
||||||
|
let ri: i32 = 0;
|
||||||
|
for (ri < env.len) { append(rejectenv, env[ri]); ri += 1; };
|
||||||
|
append(rejectenv, "WW_RUN_PREOCCUPY=1");
|
||||||
|
append(rejectenvironments, rejectenv);
|
||||||
|
si += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
let selected: []str = [ordinary, ordinarylink, testdirectory, testlink,
|
||||||
|
hidden, private, malformed, missingimport];
|
||||||
|
let selectedlabels: []str = ["direct", "symlink", "direct-test",
|
||||||
|
"symlink-test", "dot-hidden", "underscore-hidden", "malformed",
|
||||||
|
"missing-import"];
|
||||||
|
let selectedtest: []bool = [false, false, true, true, false, false,
|
||||||
|
false, false];
|
||||||
|
let sourcebefore: str = strings.dup(treesnapshot(source));
|
||||||
|
si = 0;
|
||||||
|
for (si < stages.len) {
|
||||||
|
let ri: i32 = 0;
|
||||||
|
for (ri < selected.len) {
|
||||||
|
let want: str;
|
||||||
|
if (selectedtest[ri]) {
|
||||||
|
want = strings.concat("ww: cannot run *_test.ww files (",
|
||||||
|
selected[ri], ")\n");
|
||||||
|
} else {
|
||||||
|
want = strings.concat(selected[ri],
|
||||||
|
" is a directory, should be a WW file\n");
|
||||||
|
};
|
||||||
|
let av: []str = [driverwrapper, "run", "-I", include,
|
||||||
|
selected[ri]];
|
||||||
|
expectrundirectoryrejection(root, strings.concat("run-reject-",
|
||||||
|
tags[si], "-", selectedlabels[ri]), av, rejectenvironments[si],
|
||||||
|
pidrecords[si], ctraces[si], atraces[si], ltraces[si], want);
|
||||||
|
ri += 1;
|
||||||
|
};
|
||||||
|
let boundaryav: []str = [driverwrapper, "run", "-I", include,
|
||||||
|
ordinarylink, "-I", "program-argument"];
|
||||||
|
let boundarywant: str = strings.concat(ordinarylink,
|
||||||
|
" is a directory, should be a WW file\n");
|
||||||
|
expectrundirectoryrejection(root, strings.concat("run-boundary-",
|
||||||
|
tags[si]), boundaryav, rejectenvironments[si], pidrecords[si],
|
||||||
|
ctraces[si], atraces[si], ltraces[si], boundarywant);
|
||||||
|
si += 1;
|
||||||
|
};
|
||||||
|
assert(same(sourcebefore, treesnapshot(source))
|
||||||
|
&& same(readfile(prior), "prior-public-bytes\n")
|
||||||
|
&& !directoryhasfragment(root, ".sepwork")
|
||||||
|
&& !directoryhasfragment(root, ".wwtxn.")
|
||||||
|
&& !directoryhasfragment(root, ".capture")
|
||||||
|
&& !directoryhasfragment(root, ".result")
|
||||||
|
&& !directoryhasfragment(root, ".request"));
|
||||||
|
|
||||||
|
// Concurrent preflight rejections leave independently preoccupied exact
|
||||||
|
// run paths and diagnostics untouched.
|
||||||
|
let pi: i32 = 0;
|
||||||
|
for (pi < stages.len) {
|
||||||
|
rewritefile(pidrecords[pi], ""); rewritefile(ctraces[pi], "");
|
||||||
|
rewritefile(atraces[pi], ""); rewritefile(ltraces[pi], "");
|
||||||
|
pi += 1;
|
||||||
|
};
|
||||||
|
let cav: []str = [driverwrapper, "run", ordinary];
|
||||||
|
let wav: []str = [driverwrapper, "run", ordinarylink];
|
||||||
|
let cc: exec.command;
|
||||||
|
cc.path = cav[0]; cc.argv = cav;
|
||||||
|
cc.env = rejectenvironments[0]; cc.dir = repo();
|
||||||
|
cc.stdoutpath = strings.concat(root, "/parallel-c.stdout");
|
||||||
|
cc.stderrpath = strings.concat(root, "/parallel-c.stderr");
|
||||||
|
cc.deadline = time.add(time.now(time.clock.monotonic),
|
||||||
|
(60i64 * (time.second: i64)): time.duration);
|
||||||
|
cc.grace = (100i64 * (time.millisecond: i64)): time.duration;
|
||||||
|
let wc: exec.command;
|
||||||
|
wc.path = wav[0]; wc.argv = wav;
|
||||||
|
wc.env = rejectenvironments[1]; wc.dir = repo();
|
||||||
|
wc.stdoutpath = strings.concat(root, "/parallel-ww.stdout");
|
||||||
|
wc.stderrpath = strings.concat(root, "/parallel-ww.stderr");
|
||||||
|
wc.deadline = time.add(time.now(time.clock.monotonic),
|
||||||
|
(60i64 * (time.second: i64)): time.duration);
|
||||||
|
wc.grace = (100i64 * (time.millisecond: i64)): time.duration;
|
||||||
|
let cp: exec.process;
|
||||||
|
let wp: exec.process;
|
||||||
|
exec.start(&cp, &cc); exec.start(&wp, &wc);
|
||||||
|
let cdone: bool = false;
|
||||||
|
let wdone: bool = false;
|
||||||
|
for (!cdone || !wdone) {
|
||||||
|
if (!cdone) { cdone = exec.poll(&cp); };
|
||||||
|
if (!wdone) { wdone = exec.poll(&wp); };
|
||||||
|
if (!cdone || !wdone) {
|
||||||
|
time.sleep(time.millisecond, time.clock.monotonic);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
let cownedrun: str = readfile(pidrecords[0]);
|
||||||
|
let wownedrun: str = readfile(pidrecords[1]);
|
||||||
|
let cownedmarker: str = strings.concat(cownedrun, "/observer-marker");
|
||||||
|
let wownedmarker: str = strings.concat(wownedrun, "/observer-marker");
|
||||||
|
let cownedvalid: bool = cownedrun.len > 12
|
||||||
|
&& strings.hasprefix(cownedrun, "/tmp/ww_run_");
|
||||||
|
let wownedvalid: bool = wownedrun.len > 12
|
||||||
|
&& strings.hasprefix(wownedrun, "/tmp/ww_run_");
|
||||||
|
let parallelobserved: bool = cp.result.errno == 0
|
||||||
|
&& cp.result.cleanuperrno == 0
|
||||||
|
&& cp.result.termination == exec.termination.EXIT && cp.result.code == 1
|
||||||
|
&& wp.result.errno == 0 && wp.result.cleanuperrno == 0
|
||||||
|
&& wp.result.termination == exec.termination.EXIT && wp.result.code == 1
|
||||||
|
&& readfile(cc.stdoutpath).len == 0 && readfile(wc.stdoutpath).len == 0
|
||||||
|
&& same(readfile(cc.stderrpath), strings.concat(ordinary,
|
||||||
|
" is a directory, should be a WW file\n"))
|
||||||
|
&& same(readfile(wc.stderrpath), strings.concat(ordinarylink,
|
||||||
|
" is a directory, should be a WW file\n"))
|
||||||
|
&& cownedvalid && wownedvalid
|
||||||
|
&& os.exists(cownedrun) && os.exists(wownedrun)
|
||||||
|
&& same(readfile(cownedmarker), "observer-owned\n")
|
||||||
|
&& same(readfile(wownedmarker), "observer-owned\n")
|
||||||
|
&& readfile(ctraces[0]).len == 0 && readfile(atraces[0]).len == 0
|
||||||
|
&& readfile(ltraces[0]).len == 0 && readfile(ctraces[1]).len == 0
|
||||||
|
&& readfile(atraces[1]).len == 0 && readfile(ltraces[1]).len == 0
|
||||||
|
&& same(sourcebefore, treesnapshot(source))
|
||||||
|
&& same(readfile(prior), "prior-public-bytes\n");
|
||||||
|
let cmarkerclean: i32 = -1;
|
||||||
|
let cdirclean: i32 = -1;
|
||||||
|
let wmarkerclean: i32 = -1;
|
||||||
|
let wdirclean: i32 = -1;
|
||||||
|
if (cownedvalid) {
|
||||||
|
cmarkerclean = os.remove(cownedmarker);
|
||||||
|
cdirclean = os.rmdir(cownedrun);
|
||||||
|
};
|
||||||
|
if (wownedvalid) {
|
||||||
|
wmarkerclean = os.remove(wownedmarker);
|
||||||
|
wdirclean = os.rmdir(wownedrun);
|
||||||
|
};
|
||||||
|
assert(parallelobserved && cmarkerclean == 0 && cdirclean == 0
|
||||||
|
&& wmarkerclean == 0 && wdirclean == 0
|
||||||
|
&& !os.exists(cownedrun) && !os.exists(wownedrun));
|
||||||
|
|
||||||
|
let cbuildbytes: str = "";
|
||||||
|
let cbuildartifacts: str = "";
|
||||||
|
let cteststdout: str = "";
|
||||||
|
let ctestbinary: str = "";
|
||||||
|
si = 0;
|
||||||
|
for (si < stages.len) {
|
||||||
|
let out: commandout;
|
||||||
|
let trailing: str = strings.concat(ordinary, "/");
|
||||||
|
let trailingav: []str = [driverwrapper, "run", "-I", include, trailing];
|
||||||
|
runcommandenv(root, strings.concat("run-trailing-", tags[si]), trailingav,
|
||||||
|
environments[si], (60i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 37);
|
||||||
|
assert(out.stdout.len == 0 && out.stderr.len == 0
|
||||||
|
&& !os.exists(readfile(pidrecords[si])));
|
||||||
|
let nonwwav: []str = [driverwrapper, "run", nonsuffixlink];
|
||||||
|
runcommandenv(root, strings.concat("run-non-ww-", tags[si]), nonwwav,
|
||||||
|
environments[si], (60i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 43);
|
||||||
|
assert(out.stdout.len == 0 && out.stderr.len == 0
|
||||||
|
&& !os.exists(readfile(pidrecords[si])));
|
||||||
|
let regularav: []str = [driverwrapper, "run", regular];
|
||||||
|
runcommandenv(root, strings.concat("run-regular-", tags[si]), regularav,
|
||||||
|
environments[si], (60i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 39);
|
||||||
|
assert(out.stdout.len == 0 && out.stderr.len == 0
|
||||||
|
&& !os.exists(readfile(pidrecords[si])));
|
||||||
|
let logicalav: []str = [driverwrapper, "run", "-I", include,
|
||||||
|
"domain.logical"];
|
||||||
|
runcommandenv(root, strings.concat("run-logical-", tags[si]), logicalav,
|
||||||
|
environments[si], (60i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 41);
|
||||||
|
assert(out.stdout.len == 0 && out.stderr.len == 0
|
||||||
|
&& !os.exists(readfile(pidrecords[si])));
|
||||||
|
|
||||||
|
let buildwork: str = strings.concat(root, "/build-work-", tags[si]);
|
||||||
|
let buildout: str = strings.concat(root, "/build-output-", tags[si]);
|
||||||
|
mkdirall(buildwork);
|
||||||
|
let buildav: []str = [driverwrapper, "build", "-w", buildwork,
|
||||||
|
"-I", include, "-o", buildout, ordinarylink];
|
||||||
|
runcommandenv(root, strings.concat("build-same-spelling-", tags[si]),
|
||||||
|
buildav, environments[si],
|
||||||
|
(60i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(out.stdout.len == 0 && out.stderr.len == 0 && os.exists(buildout));
|
||||||
|
let buildbytes: str = strings.dup(readfile(buildout));
|
||||||
|
let buildartifacts: str = strings.dup(artifacttreesnapshot(buildwork));
|
||||||
|
if (si == 0) {
|
||||||
|
cbuildbytes = strings.dup(buildbytes);
|
||||||
|
cbuildartifacts = strings.dup(buildartifacts);
|
||||||
|
} else {
|
||||||
|
assert(same(cbuildbytes, buildbytes)
|
||||||
|
&& same(cbuildartifacts, buildartifacts));
|
||||||
|
};
|
||||||
|
let builtav: []str = [buildout];
|
||||||
|
runcommand(root, strings.concat("built-control-", tags[si]), builtav,
|
||||||
|
time.second, &out);
|
||||||
|
expectexit(&out, 37);
|
||||||
|
|
||||||
|
let testwork: str = strings.concat(root, "/test-work-", tags[si]);
|
||||||
|
mkdirall(testwork);
|
||||||
|
let testav: []str = [driverwrapper, "test", "-w", testwork, rawtest];
|
||||||
|
runcommandenv(root, strings.concat("raw-test-control-", tags[si]), testav,
|
||||||
|
environments[si], (60i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(out.stderr.len == 0 && has(out.stdout, "raw_control ... ok\n"));
|
||||||
|
if (si == 0) { cteststdout = strings.dup(out.stdout); }
|
||||||
|
else { assert(same(cteststdout, out.stdout)); };
|
||||||
|
let testbinary: str = strings.concat(root, "/test-binary-", tags[si]);
|
||||||
|
let compileav: []str = [driverwrapper, "test", "-c", "-o",
|
||||||
|
testbinary, rawtest];
|
||||||
|
runcommandenv(root, strings.concat("raw-test-compile-", tags[si]),
|
||||||
|
compileav, environments[si],
|
||||||
|
(60i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(out.stdout.len == 0 && out.stderr.len == 0 && os.exists(testbinary));
|
||||||
|
if (si == 0) { ctestbinary = strings.dup(readfile(testbinary)); }
|
||||||
|
else { assert(same(ctestbinary, readfile(testbinary))); };
|
||||||
|
|
||||||
|
let assemblywork: str = strings.concat(root, "/assembly-work-", tags[si]);
|
||||||
|
let assemblyout: str = strings.concat(root, "/assembly-output-", tags[si]);
|
||||||
|
mkdirall(assemblywork);
|
||||||
|
rewritefile(ctraces[si], ""); rewritefile(atraces[si], "");
|
||||||
|
rewritefile(ltraces[si], "");
|
||||||
|
let assemblyav: []str = [driverwrapper, "test", "-S", "-w",
|
||||||
|
assemblywork, "-o", assemblyout, ordinarylink];
|
||||||
|
runcommandenv(root, strings.concat("directory-test-assembly-", tags[si]),
|
||||||
|
assemblyav, environments[si],
|
||||||
|
(60i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 2);
|
||||||
|
assert(out.stdout.len == 0
|
||||||
|
&& same(out.stderr, "ww test: -S needs a single test file\n")
|
||||||
|
&& !os.exists(assemblyout) && directoryisempty(assemblywork)
|
||||||
|
&& readfile(ctraces[si]).len == 0
|
||||||
|
&& readfile(atraces[si]).len == 0
|
||||||
|
&& readfile(ltraces[si]).len == 0);
|
||||||
|
si += 1;
|
||||||
|
};
|
||||||
|
assert(!directoryhasnew(root) && !directoryhasfragment(root, ".wwtxn.")
|
||||||
|
&& !directoryhasfragment(root, ".install")
|
||||||
|
&& !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.
|
||||||
|
|||||||
Reference in New Issue
Block a user