ww output: match Go exact -o parsing
This commit is contained in:
@@ -7375,7 +7375,8 @@ parse_build_flags(const char *cmd, int argc, char **argv,
|
||||
} else if (strncmp(argv[i], "-I", 2) == 0 && argv[i][2]) {
|
||||
if (include_append(cmd, incs, incsz, argv[i] + 2) < 0)
|
||||
return -1;
|
||||
} else if (strcmp(argv[i], "-o") == 0) {
|
||||
} else if (strcmp(argv[i], "-o") == 0 ||
|
||||
(strcmp(cmd, "build") == 0 && strcmp(argv[i], "--o") == 0)) {
|
||||
if (i + 1 >= argc) {
|
||||
fprintf(stderr,
|
||||
"ww %s: -o needs an argument\n", cmd);
|
||||
@@ -7383,7 +7384,16 @@ parse_build_flags(const char *cmd, int argc, char **argv,
|
||||
}
|
||||
if (cli_copy(cmd, "-o", outpath, outsz, argv[++i]) < 0)
|
||||
return -1;
|
||||
} else if (strncmp(argv[i], "-o", 2) == 0 && argv[i][2]) {
|
||||
} else if (strcmp(cmd, "build") == 0 &&
|
||||
strncmp(argv[i], "-o=", 3) == 0) {
|
||||
if (cli_copy(cmd, "-o", outpath, outsz, argv[i] + 3) < 0)
|
||||
return -1;
|
||||
} else if (strcmp(cmd, "build") == 0 &&
|
||||
strncmp(argv[i], "--o=", 4) == 0) {
|
||||
if (cli_copy(cmd, "-o", outpath, outsz, argv[i] + 4) < 0)
|
||||
return -1;
|
||||
} else if (strcmp(cmd, "run") == 0 &&
|
||||
strncmp(argv[i], "-o", 2) == 0 && argv[i][2]) {
|
||||
if (cli_copy(cmd, "-o", outpath, outsz, argv[i] + 2) < 0)
|
||||
return -1;
|
||||
} else if (argv[i][0] == '-') {
|
||||
@@ -7863,7 +7873,8 @@ do_test(int argc, char **argv)
|
||||
} else if (strncmp(argv[i], "-timeout-ms=", 12) == 0 &&
|
||||
argv[i][12] != '\0') {
|
||||
packageopts = 1;
|
||||
} else if (strcmp(argv[i], "-o") == 0) {
|
||||
} else if (strcmp(argv[i], "-o") == 0 ||
|
||||
strcmp(argv[i], "--o") == 0) {
|
||||
if (i + 1 >= argc) {
|
||||
fprintf(stderr,
|
||||
"ww test: -o needs an argument\n");
|
||||
@@ -7871,9 +7882,12 @@ do_test(int argc, char **argv)
|
||||
}
|
||||
if (cli_copy("test", "-o", outstem, sizeof outstem,
|
||||
argv[++i]) < 0) return 2;
|
||||
} else if (argv[i][1] == 'o' && argv[i][2]) {
|
||||
} else if (strncmp(argv[i], "-o=", 3) == 0) {
|
||||
if (cli_copy("test", "-o", outstem, sizeof outstem,
|
||||
argv[i] + 2) < 0) return 2;
|
||||
argv[i] + 3) < 0) return 2;
|
||||
} else if (strncmp(argv[i], "--o=", 4) == 0) {
|
||||
if (cli_copy("test", "-o", outstem, sizeof outstem,
|
||||
argv[i] + 4) < 0) return 2;
|
||||
} else if (strcmp(argv[i], "-w") == 0) {
|
||||
if (i + 1 >= argc) {
|
||||
fprintf(stderr,
|
||||
|
||||
@@ -8658,6 +8658,176 @@ executable, and retained-test-product bytes are unchanged. Build workdir format
|
||||
remains `18`, test workdir format remains `19`, and semantic storage format
|
||||
remains `3`.
|
||||
|
||||
### 11.44 Implemented exact output-option name and value semantics
|
||||
|
||||
The `ww build` and `ww test` output option has the exact registered name `o`.
|
||||
Its accepted forms are `-o VALUE`, `--o VALUE`, `-o=VALUE`, and
|
||||
`--o=VALUE`. An equals form splits at the first `=` and preserves the complete
|
||||
remaining value, including an empty value and additional `=` bytes. Repeated
|
||||
occurrences are last-value-wins. A final empty value means no effective
|
||||
explicit output: a single command uses its ordinary default, a multi-command
|
||||
build performs its ordinary no-public-output build, a running test retains no
|
||||
copy, and compile-only testing uses its ordinary default retained name.
|
||||
Concatenated names such as `-oVALUE` and `--oVALUE` are unknown flags rather
|
||||
than output requests. Build option parsing stops at the first root operand;
|
||||
test parsing continues to recognize known test options, including exact `o`,
|
||||
on either side of its package operands.
|
||||
|
||||
#### Pinned evidence and fact classification
|
||||
|
||||
The sole authority is official Go 1.26.5 at
|
||||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||||
|
||||
- `init` registers exactly string flag name `o` for the build command in
|
||||
[`cmd/go/internal/work/build.go`, lines 241–248](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L241-L248),
|
||||
and `invoke` parses that flag set before passing only remaining operands to
|
||||
`runBuild` in
|
||||
[`cmd/go/main.go`, lines 290–322](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/main.go#L290-L322).
|
||||
- `(*FlagSet).parseOne` accepts one or two leading dashes, splits the first
|
||||
`=`, consumes the next argument only when there was no equals delimiter, and
|
||||
rejects an unregistered concatenated name in
|
||||
[`flag/flag.go`, lines 1074–1146](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/flag/flag.go#L1074-L1146).
|
||||
`(*FlagSet).Parse` stops at the first non-flag operand at lines 1149–1176.
|
||||
`stringValue.Set` and `(*FlagSet).Set` overwrite a repeated string value at
|
||||
lines 240–250 and 494–528. `runBuild` derives effective explicit output from
|
||||
the final value's nonzero length and otherwise selects its default behavior
|
||||
in
|
||||
[`cmd/go/internal/work/build.go`, lines 459–478](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L459-L478).
|
||||
- Build command testdata uses an equals-delimited output successfully in
|
||||
[`version_buildvcs_nested.txt`, line 57](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/version_buildvcs_nested.txt#L57).
|
||||
`testParse` exercises exact names with two leading dashes and separate
|
||||
values at
|
||||
[`flag_test.go`, lines 164–215](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/flag/flag_test.go#L164-L215),
|
||||
`TestUserDefined` asserts an equals-delimited string value at lines 251–267,
|
||||
and `TestUsage` asserts unknown-flag failure at lines 153–161.
|
||||
- Test command `init` registers exactly string flag name `o` in
|
||||
[`cmd/go/internal/test/testflag.go`, lines 32–38](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/testflag.go#L32-L38).
|
||||
`cmdflag.ParseOne` accepts one or two dashes, cuts the first `=`, preserves
|
||||
empty and remaining-equals value bytes, and rejects unknown names in
|
||||
[`cmd/go/internal/cmdflag/flag.go`, lines 53–118](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/cmdflag/flag.go#L53-L118).
|
||||
`testFlags` recognizes known flags before and after the package list and
|
||||
rejects an unknown flag with `-c` in
|
||||
[`cmd/go/internal/test/testflag.go`, lines 219–349](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/testflag.go#L219-L349).
|
||||
`testNeedBinary` and the output-classification branch treat final empty
|
||||
`testO` as no explicit retained destination in
|
||||
[`cmd/go/internal/test/test.go`, lines 631–646 and 771–781](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L631-L781).
|
||||
- Official command testdata uses compile-only test output successfully in
|
||||
[`devnull.txt`, lines 3–8](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/devnull.txt#L3-L8)
|
||||
and
|
||||
[`test_race_tag.txt`, lines 1–9](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_race_tag.txt#L1-L9).
|
||||
[`test2json_interrupt.txt`, line 10](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test2json_interrupt.txt#L10)
|
||||
places `-o` after a package operand, while
|
||||
[`test_flag.txt`, lines 11–16](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_flag.txt#L11-L16)
|
||||
asserts unknown-flag rejection with `-c` across supported placements.
|
||||
|
||||
Those registrations, parser branches, effective-output branches, and official
|
||||
assertions are **behavior directly implemented or asserted by pinned Go**.
|
||||
Applying their exact-name, first-equals, final-value, and command-placement
|
||||
rules to WW's local command surface while retaining WW's diagnostic wording is
|
||||
**behavior derived from the pinned implementation**. The measured WW matrix
|
||||
below is **directly measured WW behavior**; no installed host Go result is used
|
||||
as authority.
|
||||
|
||||
#### Direct pre-fix Cstage and WWstage matrix
|
||||
|
||||
Both stages had identical pre-fix behavior in every row:
|
||||
|
||||
| Route and spelling | Directly measured pre-fix result |
|
||||
| --- | --- |
|
||||
| single build, `-o=name` | exited 0 with empty streams, left `name` absent, and published executable `=name` |
|
||||
| single build, `-oname` | exited 0 with empty streams and incorrectly accepted the concatenated name |
|
||||
| single build, `--o name` or `--o=name` | exited 2 with empty stdout and byte-identical `ww build: unknown flag\n` stderr |
|
||||
| single build, final `-o=` | exited 0 with empty streams and published literal file `=` rather than the default command name |
|
||||
| build values containing `=` | retained an erroneous leading `=`; repeated separate forms were already last-value-wins |
|
||||
| build option after the first root | remained package input rather than being reparsed, matching the required placement boundary |
|
||||
| two-command coordinator, `-o=DIR/` | published both products beneath a literal leading-`=` directory |
|
||||
| two-command coordinator, `-oDIR/` | incorrectly accepted the joined name and published beneath the requested directory |
|
||||
| two-command coordinator, final `-o=` | exited 2 as `cannot use -o with multiple packages` instead of selecting no effective explicit output |
|
||||
| compile-only directory test, `-o=name` | exited 0 with empty streams, left `name` absent, and published test binary `=name` |
|
||||
| compile-only directory test, `-oname` | incorrectly accepted the concatenated name and published that retained binary |
|
||||
| compile-only directory test, `--o=name` | exited 2 with empty stdout and byte-identical `ww test: unknown flag\n` stderr |
|
||||
| compile-only directory test, final `-o=` or a value containing `=` | published literal `=` or an erroneous leading-`=` destination |
|
||||
| test `-o` after its package operand | was already recognized, matching the required test placement boundary |
|
||||
|
||||
The wrong-path single-build executables were stage-byte-identical 4,268-byte
|
||||
files with SHA-256
|
||||
`866c1eb875dad271d37572f43fb9d9b0eb6a2344d2e61646e655bb09f7909bf6`.
|
||||
The wrong-path retained test binaries were stage-byte-identical 112,829-byte
|
||||
files with SHA-256
|
||||
`5ea3ac9add844dc4cd98cc07fb64816415b5e3c03745dc4cc756ec093cf5cea7`.
|
||||
The build and test unknown-flag diagnostics were respectively 23 and 22 bytes,
|
||||
also byte-identical between Cstage and WWstage. These byte counts and hashes
|
||||
describe only the direct pre-fix measurements.
|
||||
|
||||
#### Ownership and complete four-axis result
|
||||
|
||||
The Cstage command owners are `parse_build_flags` and `do_test` in
|
||||
`cmd/ww/main.c`. Their WWstage semantic twins are `dobuild` and `dotest` in
|
||||
`selfhost/cmd/ww/main.ww`. The shared multi-package owner is
|
||||
`packagecommand` in `internal/wwpackage/package.ww`. Each recognizes exact
|
||||
one-/two-dash separate/equals forms, replaces prior occurrences with the final
|
||||
value, and derives effective explicit-output state from that final value's
|
||||
non-emptiness. The build parser retains its first-root stop, while test and the
|
||||
coordinator retain their established after-package recognition. `dorun` and
|
||||
the shared `run` route are not changed. The compiler, assembler, archiver,
|
||||
linker, runtime, package checker, and import resolver do not own this rule.
|
||||
|
||||
- **Go-like build:** exact accepted forms select the same established output
|
||||
path as separate `-o VALUE`; a final empty value selects the existing
|
||||
default/no-public-output branch. Invalid concatenated names reject before
|
||||
loading, graph or action construction, producers, publication, or runtime.
|
||||
- **Go-like test:** the same exact forms select retained destinations on both
|
||||
sides of package operands. Final empty means no running-test retention or
|
||||
the normal compile-only default. Discovery, variants, generated main,
|
||||
filtering, execution, accounting, result annotation, and absence of a
|
||||
test-result cache do not change.
|
||||
- **Go-like package:** output bytes remain presentation metadata. Source
|
||||
eligibility, package clauses, declared names, variants, command
|
||||
classification, canonical package representatives, graph nodes, actions,
|
||||
symbols, artifacts, and persistence keys are unchanged.
|
||||
- **Go-like import:** output spelling creates no binding or edge and changes no
|
||||
dotted import spelling, alias, search, local/vendor/internal rule,
|
||||
visibility, cycle, initialization order, canonical identity, or `.wwi`
|
||||
ownership.
|
||||
|
||||
#### Loading, lifecycle, parity, and proof
|
||||
|
||||
Accepted forms enter the same existing loading, graph, scheduling, compiler,
|
||||
assembler, archiver, linker, runtime, publication, persistence, reuse, and
|
||||
invalidation paths as `-o VALUE`. They add no action, process, transaction,
|
||||
cache, key, artifact byte, or runtime state. Producer or runtime failure,
|
||||
late output rejection, rollback, prior-state preservation, concurrent
|
||||
publication, interruption, and process-group cleanup therefore retain their
|
||||
established owners and results. Output installation keeps the existing
|
||||
transaction, object-safety, mode, null-device, output-directory, and
|
||||
running-retained-test guard rules.
|
||||
|
||||
Invalid concatenated names stop before all loading and work, create no
|
||||
diagnostic competitor or product, and leave no unit, interface, assembly,
|
||||
object, archive, executable, retained test binary, capture, output prefix,
|
||||
`.new`, `.install`, `.wwtxn.*`, or scratch residue. A final empty value cannot
|
||||
create literal `=`, `=.sepwork`, or transaction residue. Cold and warm
|
||||
accepted requests use the ordinary publication and reuse paths; changing only
|
||||
an accepted spelling does not rekey semantic work. Independent concurrent
|
||||
requests own independent argument state, workdirs, stages, captures, and
|
||||
outputs. Build starts no runtime; running tests keep their private executable
|
||||
and publish only after successful execution.
|
||||
|
||||
The WW-native `output_flag_exact_name_and_value_semantics` observer is the
|
||||
focused owner for both public stages and all three parser routes. It covers the
|
||||
four accepted forms, extra and empty equals values, repetition, concatenated
|
||||
name rejection, build/test placement controls, multi-command behavior,
|
||||
diagnostic parity, runnable and retained artifact-byte parity, warm reuse, and
|
||||
absence of literal-equals and transaction residue. Existing transaction,
|
||||
producer/runtime failure, rollback, concurrency, interruption, output-mode,
|
||||
and cleanup observers remain authoritative for the unchanged downstream
|
||||
mechanisms. Post-fix byte counts and hashes are recorded only after direct
|
||||
focused measurement; this section does not infer them from the implementation.
|
||||
|
||||
This is command parsing and output presentation only. No persisted-byte
|
||||
contract changes: build workdir format remains `18`, test workdir format
|
||||
remains `19`, and semantic storage format remains `3`.
|
||||
|
||||
## 12. Candidate architectures and hard-gate decision
|
||||
|
||||
Five candidates were developed as coherent systems, not as feature bins.
|
||||
|
||||
35
docs/spec.md
35
docs/spec.md
@@ -344,7 +344,19 @@ ImportPath = ident { "." ident } .
|
||||
arguments and result; this rule does not adopt Go's source signature. An
|
||||
ordinary import of a package declared `main` is rejected, except for the
|
||||
toolchain's colocated external-test wiring.
|
||||
- For `ww build`, an explicit `-o` names an output directory when ordinary
|
||||
- For `ww build`, the output-option name is exactly `o`. The accepted forms are
|
||||
`-o VALUE`, `--o VALUE`, `-o=VALUE`, and `--o=VALUE`. An equals form splits
|
||||
at its first `=` and preserves every later byte, including further `=`
|
||||
characters; an empty value is valid. Repetition is last-value-wins, and a
|
||||
final empty value means that there is no effective explicit output, so the
|
||||
ordinary default-output or no-public-output rule applies. A concatenated
|
||||
spelling such as `-oVALUE` or `--oVALUE` is an unknown flag, not an output
|
||||
option. Build option parsing stops at the first package or source operand;
|
||||
later flag-like arguments remain operands and are not reparsed as `-o`.
|
||||
These spelling and placement rules select only caller-visible output
|
||||
disposition and never supply package, import, graph, action, symbol,
|
||||
artifact, `.wwi`, or persistence identity.
|
||||
A nonempty effective `-o` names an output directory when ordinary
|
||||
`stat` reports an existing directory (following symlinks) or its spelling
|
||||
ends in `/`. This classification is independent of whether one or many
|
||||
package roots were requested. Each selected command is published beneath
|
||||
@@ -771,11 +783,22 @@ coordinator reports that successful validation exactly as
|
||||
`? <package> [no test files]\n`.
|
||||
|
||||
Every test-bearing directory product links one request-private runnable.
|
||||
`-c` retains an executable copy and suppresses its execution; `-o` retains a
|
||||
copy at the named destination and still executes unless `-c` is present. With
|
||||
no explicit output, `-c` writes `<import-leaf>.test` in the invocation
|
||||
directory. An output ending in `/` or naming an existing directory receives
|
||||
that basename and may have missing parent directories created. One
|
||||
The test output-option name is exactly `o`, with the accepted forms `-o VALUE`,
|
||||
`--o VALUE`, `-o=VALUE`, and `--o=VALUE`. Equals forms split only at their
|
||||
first `=` and preserve an empty value or any additional `=` bytes. Repeated
|
||||
occurrences are last-value-wins. A final empty value means no effective
|
||||
explicit output and therefore requests no running-test retention; with `-c`,
|
||||
the ordinary default retained name applies. A concatenated `-oVALUE` or
|
||||
`--oVALUE` is unknown. Unlike build option parsing, known test options,
|
||||
including these exact output forms, are recognized before or after package
|
||||
operands. Invalid output-option names reject before package loading, product
|
||||
construction, execution, or publication.
|
||||
`-c` retains an executable copy and suppresses its execution; a nonempty
|
||||
effective `-o` retains a copy at the named destination and still executes
|
||||
unless `-c` is present. With no effective explicit output, `-c` writes
|
||||
`<import-leaf>.test` in the invocation directory. An output ending in `/` or
|
||||
naming an existing directory receives that basename and may have missing
|
||||
parent directories created. One
|
||||
non-directory output may name only one package. Multiple packages whose
|
||||
visible import leaves would produce the same test-binary name reject before
|
||||
tools or output creation; exact `/dev/null` is the discard exception. It keeps
|
||||
|
||||
@@ -236,13 +236,23 @@ warning on stderr and accounting on stdout because no coordinator combines its
|
||||
descriptors or emits a package result.
|
||||
|
||||
Directory test binaries are always linked under the coordinator's temporary
|
||||
product root. `-c` independently requests a caller-visible executable copy and
|
||||
suppresses execution. `-o` independently requests a copy and still runs the
|
||||
temporary binary unless `-c` is also present. Without `-o`, `-c` publishes
|
||||
`<import-leaf>.test` in the invocation directory; an output ending in `/` or
|
||||
naming an existing directory receives one such name per selected package and
|
||||
missing parents are created. A single non-directory output is legal for one
|
||||
package only. Multi-package non-directory output and duplicate visible binary
|
||||
product root. The retained-output option has the exact registered name `o` and
|
||||
accepts `-o VALUE`, `--o VALUE`, `-o=VALUE`, and `--o=VALUE`. An equals form
|
||||
splits only at its first `=`, preserving an empty value and any later `=`
|
||||
bytes. Repeated occurrences are last-value-wins. A final empty value is no
|
||||
effective explicit output: it requests no retained copy for a running test,
|
||||
while `-c` falls back to the ordinary `<import-leaf>.test` name. Concatenated
|
||||
`-oVALUE` and `--oVALUE` spell unknown flags and reject before loading, product
|
||||
construction, tools, execution, or publication. Known test flags, including
|
||||
these exact output forms, remain recognized before or after package operands.
|
||||
`-c` independently requests a caller-visible executable copy and suppresses
|
||||
execution. A nonempty effective `-o` independently requests a copy and still
|
||||
runs the temporary binary unless `-c` is also present. Without an effective
|
||||
explicit output, `-c` publishes `<import-leaf>.test` in the invocation
|
||||
directory; an output ending in `/` or naming an existing directory receives
|
||||
one such name per selected package and missing parents are created. A single
|
||||
non-directory output is legal for one package only. Multi-package
|
||||
non-directory output and duplicate visible binary
|
||||
names reject before tools; exact `/dev/null` discards every copy and permits
|
||||
duplicate names. The private test link still runs unless `-c` suppresses it;
|
||||
the raw single-file compatibility route also links into driver-owned private
|
||||
|
||||
@@ -2055,16 +2055,20 @@ export fn packagecommand(args: []str) int = {
|
||||
i += 1;
|
||||
continue;
|
||||
};
|
||||
if (strings.compare(a, "-o") == 0) {
|
||||
if (strings.compare(a, "-o") == 0
|
||||
|| strings.compare(a, "--o") == 0) {
|
||||
if (i + 1 >= args.len) { pkgusage(); return 2; };
|
||||
outname = args[i + 1];
|
||||
explicitout = true;
|
||||
explicitout = outname.len != 0;
|
||||
i += 2;
|
||||
continue;
|
||||
};
|
||||
if (strings.hasprefix(a, "-o") && a.len > 2) {
|
||||
outname = a[2:a.len];
|
||||
explicitout = true;
|
||||
if (strings.hasprefix(a, "-o=")
|
||||
|| strings.hasprefix(a, "--o=")) {
|
||||
let valueoff: i32 = 3;
|
||||
if (a[1] == '-') { valueoff = 4; };
|
||||
outname = a[valueoff:a.len];
|
||||
explicitout = outname.len != 0;
|
||||
i += 1;
|
||||
continue;
|
||||
};
|
||||
|
||||
@@ -8853,19 +8853,25 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
};
|
||||
libs[nlibs] = nm;
|
||||
nlibs += 1;
|
||||
} else { if (p[1u64] == 111u8) { // '-o'
|
||||
if (p[2u64] != 0u8) {
|
||||
outflag = p + 2u64;
|
||||
} else { if (cstreqlit(p, "-o") || cstreqlit(p, "--o")
|
||||
|| (p[1u64] == 111u8 && p[2u64] == 61u8)
|
||||
|| (p[1u64] == 45u8 && p[2u64] == 111u8
|
||||
&& p[3u64] == 61u8)) {
|
||||
if (p[1u64] == 111u8 && p[2u64] == 61u8) {
|
||||
outflag = p + 3u64;
|
||||
} else { if (p[1u64] == 45u8
|
||||
&& p[2u64] == 111u8 && p[3u64] == 61u8) {
|
||||
outflag = p + 4u64;
|
||||
} else {
|
||||
if (i + 1 >= argc) {
|
||||
cerr("ww build: -o needs an argument\n");
|
||||
return 2;
|
||||
};
|
||||
i += 1;
|
||||
outflag = argv[i];
|
||||
};
|
||||
if (!clipathfits("build", "-o", outflag)) { return 2; };
|
||||
} else { if (p[1u64] == 119u8) { // '-w'
|
||||
outflag = argv[i];
|
||||
}; };
|
||||
if (!clipathfits("build", "-o", outflag)) { return 2; };
|
||||
} else { if (p[1u64] == 119u8) { // '-w'
|
||||
if (p[2u64] != 0u8) {
|
||||
workdir = p + 2u64;
|
||||
} else {
|
||||
@@ -8892,6 +8898,7 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
if (outflag != nil && outflag[0u64] == 0u8) { outflag = nil; };
|
||||
|
||||
if (src == nil) {
|
||||
let dot: [2]u8 = ['.': u8, 0u8];
|
||||
@@ -9656,19 +9663,26 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
&& ps.len > 12) {
|
||||
packageopts = true; i += 1; continue;
|
||||
};
|
||||
if (p[1u64] == 111u8) { // '-o'
|
||||
if (p[2u64] != 0u8) {
|
||||
outstem = p + 2u64;
|
||||
if (cstreqlit(p, "-o") || cstreqlit(p, "--o")
|
||||
|| (p[1u64] == 111u8 && p[2u64] == 61u8)
|
||||
|| (p[1u64] == 45u8 && p[2u64] == 111u8
|
||||
&& p[3u64] == 61u8)) {
|
||||
if (p[1u64] == 111u8 && p[2u64] == 61u8) {
|
||||
outstem = p + 3u64;
|
||||
} else { if (p[1u64] == 45u8
|
||||
&& p[2u64] == 111u8 && p[3u64] == 61u8) {
|
||||
outstem = p + 4u64;
|
||||
} else {
|
||||
if (i + 1 >= argc) {
|
||||
cerr("ww test: -o needs an argument\n");
|
||||
return 2;
|
||||
};
|
||||
i += 1;
|
||||
outstem = argv[i];
|
||||
outstem = argv[i];
|
||||
};
|
||||
if (!clipathfits("test", "-o", outstem)) { return 2; };
|
||||
i += 1; continue;
|
||||
};
|
||||
if (!clipathfits("test", "-o", outstem)) { return 2; };
|
||||
i += 1; continue;
|
||||
};
|
||||
if (p[1u64] == 119u8) { // '-w'
|
||||
if (p[2u64] != 0u8) {
|
||||
@@ -9691,6 +9705,7 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
if (outstem != nil && outstem[0u64] == 0u8) { outstem = nil; };
|
||||
if (target == nil) {
|
||||
let dot: [2]u8 = ['.': u8, 0u8];
|
||||
target = &dot[0];
|
||||
|
||||
@@ -13816,6 +13816,435 @@ fn runtimepath(relative: str) str = {
|
||||
clean(root);
|
||||
};
|
||||
|
||||
@test fn output_flag_exact_name_and_value_semantics() void = {
|
||||
let root: str = fresh();
|
||||
let source: str = strings.concat(root, "/source");
|
||||
let multi_a: str = strings.concat(source, "/alpha");
|
||||
let multi_b: str = strings.concat(source, "/beta");
|
||||
let tests: str = strings.concat(source, "/tests");
|
||||
let outputs: str = strings.concat(root, "/outputs");
|
||||
mkdirall(source); mkdirall(multi_a); mkdirall(multi_b);
|
||||
mkdirall(tests); mkdirall(outputs);
|
||||
let single: str = strings.concat(source, "/single.ww");
|
||||
writefile(single,
|
||||
"package main;\nfn main() i32 = { return 29; };\n");
|
||||
writefile(strings.concat(multi_a, "/main.ww"),
|
||||
"package main;\nfn main() i32 = { return 31; };\n");
|
||||
writefile(strings.concat(multi_b, "/main.ww"),
|
||||
"package main;\nfn main() i32 = { return 37; };\n");
|
||||
writefile(strings.concat(tests, "/tests.ww"),
|
||||
"package exactflags;\nfn value() i32 = { return 41; };\n");
|
||||
writefile(strings.concat(tests, "/tests_test.ww"), strings.concat(
|
||||
"package exactflags;\n",
|
||||
"@test fn exact() void = { assert(value() == 41); };\n"));
|
||||
let rawtest: str = strings.concat(source, "/raw_test.ww");
|
||||
writefile(rawtest, strings.concat(
|
||||
"package exactraw;\n",
|
||||
"@test fn raw_exact() void = { assert(true); };\n"));
|
||||
|
||||
let compilerwrapper: str = strings.concat(root, "/output-flag-w6c.sh");
|
||||
writeexecutable(compilerwrapper, strings.concat(
|
||||
"#!/bin/sh\nprintf '%s\\n' \"$*\" >> \"$WW_OUTPUT_FLAG_TRACE\"\n",
|
||||
"exec \"$WW_OUTPUT_FLAG_REAL_C\" \"$@\"\n"));
|
||||
let stages: []str = ["ww", "ww_ww"];
|
||||
let compilers: []str = ["w6c", "w6c_ww"];
|
||||
let tags: []str = ["c", "ww"];
|
||||
let forms: []str = ["one-separate", "one-equals", "two-separate",
|
||||
"two-equals"];
|
||||
let buildref: str = "";
|
||||
let testref: str = "";
|
||||
let alpharef: str = "";
|
||||
let betaref: str = "";
|
||||
let rawref: str = "";
|
||||
let rejectrefs: []str = ["", "", "", "", ""];
|
||||
let coordinatorrejectref: str = "";
|
||||
let buildmissingref: str = "";
|
||||
let testmissingref: str = "";
|
||||
let stopref: str = "";
|
||||
let baseenv: []str = os.getenvs();
|
||||
let out: commandout;
|
||||
let si: i32 = 0;
|
||||
for (si < stages.len) {
|
||||
let trace: str = strings.concat(root, "/output-flag-", tags[si],
|
||||
".trace");
|
||||
writefile(trace, "");
|
||||
let env: []str = alloc([], (baseenv.len + 3): u64)!;
|
||||
let ei: i32 = 0;
|
||||
for (ei < baseenv.len) {
|
||||
if (!strings.hasprefix(baseenv[ei], "WW_W6C=")
|
||||
&& !strings.hasprefix(baseenv[ei], "WW_OUTPUT_FLAG_")) {
|
||||
append(env, baseenv[ei]);
|
||||
};
|
||||
ei += 1;
|
||||
};
|
||||
append(env, strings.concat("WW_W6C=", compilerwrapper));
|
||||
append(env, strings.concat("WW_OUTPUT_FLAG_REAL_C=",
|
||||
driver(compilers[si])));
|
||||
append(env, strings.concat("WW_OUTPUT_FLAG_TRACE=", trace));
|
||||
let ignoredrunout: str = strings.concat(outputs, "/ignored-run-",
|
||||
tags[si]);
|
||||
let runcontrol: []str = [driver(stages[si]), "run", "-I", source,
|
||||
strings.concat("-o", ignoredrunout), single];
|
||||
runcommand(root, strings.concat("output-flag-run-control-", tags[si]),
|
||||
runcontrol, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 29);
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0
|
||||
&& !os.exists(ignoredrunout));
|
||||
|
||||
// Exact output names change only publication. Distinct accepted
|
||||
// spellings retain the same action and executable bytes.
|
||||
let buildwork: str = strings.concat(root, "/build-work-", tags[si]);
|
||||
mkdirall(buildwork);
|
||||
let fi: i32 = 0;
|
||||
for (fi < forms.len) {
|
||||
let binary: str = strings.concat(outputs, "/build-", tags[si],
|
||||
"-", forms[fi], "=tail");
|
||||
let av: []str = [driver(stages[si]), "build", "-w", buildwork,
|
||||
"-I", source];
|
||||
if (fi == 0) { append(av, "-o"); append(av, binary); }
|
||||
else if (fi == 1) { append(av, strings.concat("-o=", binary)); }
|
||||
else if (fi == 2) { append(av, "--o"); append(av, binary); }
|
||||
else { append(av, strings.concat("--o=", binary)); };
|
||||
append(av, single);
|
||||
rewritefile(trace, "");
|
||||
runcommandenv(root, strings.concat("output-flag-build-", tags[si],
|
||||
"-", forms[fi]), av, env,
|
||||
(60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0
|
||||
&& os.exists(binary));
|
||||
if (fi == 0) { assert(readfile(trace).len != 0); }
|
||||
else { assert(readfile(trace).len == 0); };
|
||||
let bytes: str = readfile(binary);
|
||||
if (buildref.len == 0) { buildref = strings.dup(bytes); }
|
||||
else { assert(same(buildref, bytes)); };
|
||||
let runav: []str = [binary];
|
||||
runcommand(root, strings.concat("output-flag-build-run-", tags[si],
|
||||
"-", forms[fi]), runav, time.second, &out);
|
||||
expectexit(&out, 29);
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0);
|
||||
fi += 1;
|
||||
};
|
||||
|
||||
// Repeated string flags are last-wins. A final empty value returns to
|
||||
// default naming and cannot create a file or scratch tree named '='.
|
||||
let stale: str = strings.concat(outputs, "/stale-build-", tags[si]);
|
||||
let winner: str = strings.concat(outputs, "/winner-build-", tags[si],
|
||||
"=last");
|
||||
let lastav: []str = [driver(stages[si]), "build", "-w", buildwork,
|
||||
"-I", source, "-o", stale, strings.concat("--o=", winner), single];
|
||||
rewritefile(trace, "");
|
||||
runcommandenv(root, strings.concat("output-flag-last-", tags[si]),
|
||||
lastav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0
|
||||
&& !os.exists(stale) && same(buildref, readfile(winner))
|
||||
&& readfile(trace).len == 0);
|
||||
let defaultbin: str = strings.concat(root, "/single");
|
||||
let emptyav: []str = [driver(stages[si]), "build", "-w", buildwork,
|
||||
"-I", source, "-o", stale, "-o=", single];
|
||||
rewritefile(trace, "");
|
||||
runcommandenvdir(root, strings.concat("output-flag-empty-", tags[si]),
|
||||
emptyav, env, root,
|
||||
(60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0
|
||||
&& !os.exists(stale) && same(buildref, readfile(defaultbin))
|
||||
&& readfile(trace).len == 0
|
||||
&& !os.exists(strings.concat(root, "/="))
|
||||
&& !os.exists(strings.concat(root, "/=.sepwork")));
|
||||
assert(os.remove(defaultbin) == 0);
|
||||
clean(strings.concat(defaultbin, ".sepwork"));
|
||||
|
||||
// Build parsing stops at its first operand: a later flag-like value is
|
||||
// package input, not a second output option.
|
||||
let early: str = strings.concat(outputs, "/early");
|
||||
let late: str = strings.concat(outputs, "/late");
|
||||
let stopav: []str = [driver(stages[si]), "build", "-I", source,
|
||||
"-o", early, single, strings.concat("--o=", late)];
|
||||
runcommand(root, strings.concat("output-flag-stop-", tags[si]), stopav,
|
||||
(60i64 * (time.second: i64)): time.duration, &out);
|
||||
assert(out.termination == exec.termination.EXIT && out.code != 0);
|
||||
assert(out.stdout.len == 0 && !has(out.stderr, "unknown flag")
|
||||
&& !os.exists(early) && !os.exists(late));
|
||||
if (si == 0) { stopref = strings.dup(out.stderr); }
|
||||
else { assert(same(stopref, out.stderr)); };
|
||||
|
||||
// Joined names are unknown before loading, work creation, or output.
|
||||
let ri: i32 = 0;
|
||||
for (ri < 2) {
|
||||
let badout: str = strings.concat(outputs, "/bad-build-", tags[si],
|
||||
"-", forms[ri]);
|
||||
let badwork: str = strings.concat(root, "/bad-build-work-", tags[si],
|
||||
"-", forms[ri]);
|
||||
let prefix: str = "-o";
|
||||
if (ri != 0) { prefix = "--o"; };
|
||||
let joined: str = strings.concat(prefix, badout);
|
||||
let badav: []str = [driver(stages[si]), "build", "-w", badwork,
|
||||
"-I", source, joined, single];
|
||||
runcommand(root, strings.concat("output-flag-reject-build-", tags[si],
|
||||
"-", forms[ri]), badav, time.second, &out);
|
||||
expectexit(&out, 2);
|
||||
assert(out.stdout.len == 0
|
||||
&& same(out.stderr, "ww build: unknown flag\n")
|
||||
&& !os.exists(badout) && !os.exists(badwork));
|
||||
if (si == 0) { rejectrefs[ri] = strings.dup(out.stderr); }
|
||||
else { assert(same(rejectrefs[ri], out.stderr)); };
|
||||
ri += 1;
|
||||
};
|
||||
let buildmissingwork: str = strings.concat(root,
|
||||
"/missing-build-work-", tags[si]);
|
||||
let buildmissing: []str = [driver(stages[si]), "build", "-w",
|
||||
buildmissingwork, "-I", source, "--o"];
|
||||
runcommand(root, strings.concat("output-flag-missing-build-", tags[si]),
|
||||
buildmissing, time.second, &out);
|
||||
expectexit(&out, 2);
|
||||
assert(out.stdout.len == 0
|
||||
&& same(out.stderr, "ww build: -o needs an argument\n")
|
||||
&& !os.exists(buildmissingwork));
|
||||
if (si == 0) { buildmissingref = strings.dup(out.stderr); }
|
||||
else { assert(same(buildmissingref, out.stderr)); };
|
||||
|
||||
// Two roots exercise coordinator output planning. The second spelling
|
||||
// reuses the first request's compiled actions, and final empty performs
|
||||
// the established no-public-output multi-build.
|
||||
let multiwork: str = strings.concat(root, "/multi-work-", tags[si]);
|
||||
mkdirall(multiwork);
|
||||
let multione: str = strings.concat(root, "/multi-one-", tags[si], "/");
|
||||
let multiav: []str = [driver(stages[si]), "build", "-w", multiwork,
|
||||
"-I", source, strings.concat("--o=", multione), multi_a, multi_b];
|
||||
rewritefile(trace, "");
|
||||
runcommandenvdir(root, strings.concat("output-flag-multi-one-", tags[si]),
|
||||
multiav, env, root,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0
|
||||
&& readfile(trace).len != 0);
|
||||
let alphaone: str = strings.concat(multione, "alpha");
|
||||
let betaone: str = strings.concat(multione, "beta");
|
||||
if (alpharef.len == 0) {
|
||||
alpharef = readfile(alphaone); betaref = readfile(betaone);
|
||||
} else {
|
||||
assert(same(alpharef, readfile(alphaone))
|
||||
&& same(betaref, readfile(betaone)));
|
||||
};
|
||||
let alpharun: []str = [alphaone];
|
||||
runcommand(root, strings.concat("output-flag-alpha-run-", tags[si]),
|
||||
alpharun, time.second, &out);
|
||||
expectexit(&out, 31);
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0);
|
||||
let betarun: []str = [betaone];
|
||||
runcommand(root, strings.concat("output-flag-beta-run-", tags[si]),
|
||||
betarun, time.second, &out);
|
||||
expectexit(&out, 37);
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0);
|
||||
let multitwo: str = strings.concat(root, "/multi-two-", tags[si], "/");
|
||||
let warmav: []str = [driver(stages[si]), "build", "-w", multiwork,
|
||||
"-I", source, "-o", multitwo, multi_a, multi_b];
|
||||
rewritefile(trace, "");
|
||||
runcommandenvdir(root, strings.concat("output-flag-multi-warm-", tags[si]),
|
||||
warmav, env, root,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0
|
||||
&& readfile(trace).len == 0
|
||||
&& same(alpharef, readfile(strings.concat(multitwo, "alpha")))
|
||||
&& same(betaref, readfile(strings.concat(multitwo, "beta"))));
|
||||
let unusedmulti: str = strings.concat(root, "/multi-unused-", tags[si],
|
||||
"/");
|
||||
let multiempty: []str = [driver(stages[si]), "build", "-w", multiwork,
|
||||
"-I", source, "-o", unusedmulti, "--o=", multi_a, multi_b];
|
||||
rewritefile(trace, "");
|
||||
runcommandenvdir(root, strings.concat("output-flag-multi-empty-", tags[si]),
|
||||
multiempty, env, root,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0
|
||||
&& readfile(trace).len == 0 && !os.exists(unusedmulti)
|
||||
&& !os.exists(strings.concat(root, "/alpha"))
|
||||
&& !os.exists(strings.concat(root, "/beta")));
|
||||
let multibadout: str = strings.concat(outputs, "/bad-multi-", tags[si]);
|
||||
let multibadwork: str = strings.concat(root, "/bad-multi-work-", tags[si]);
|
||||
let multibad: []str = [driver(stages[si]), "build", "-w", multibadwork,
|
||||
"-I", source, strings.concat("--o", multibadout), multi_a, multi_b];
|
||||
runcommand(root, strings.concat("output-flag-reject-multi-", tags[si]),
|
||||
multibad, time.second, &out);
|
||||
expectexit(&out, 2);
|
||||
assert(out.stdout.len == 0
|
||||
&& same(out.stderr, "ww build: unknown flag\n")
|
||||
&& !os.exists(multibadout) && !os.exists(multibadwork));
|
||||
if (si == 0) { rejectrefs[4] = strings.dup(out.stderr); }
|
||||
else { assert(same(rejectrefs[4], out.stderr)); };
|
||||
let directbadout: str = strings.concat(outputs,
|
||||
"/bad-direct-coordinator-", tags[si]);
|
||||
let directbadwork: str = strings.concat(root,
|
||||
"/bad-direct-coordinator-work-", tags[si]);
|
||||
let directbad: []str = [driver("wwtest"), "package",
|
||||
"--ww-operation", "build", "--ww-driver", driver(stages[si]),
|
||||
"-w", directbadwork, "-I", source,
|
||||
strings.concat("-o", directbadout), multi_a, multi_b];
|
||||
runcommand(root, strings.concat("output-flag-reject-coordinator-",
|
||||
tags[si]), directbad, time.second, &out);
|
||||
expectexit(&out, 2);
|
||||
assert(out.stdout.len == 0 && has(out.stderr, "usage: wwtest package")
|
||||
&& !os.exists(directbadout) && !os.exists(directbadwork));
|
||||
if (si == 0) { coordinatorrejectref = strings.dup(out.stderr); }
|
||||
else { assert(same(coordinatorrejectref, out.stderr)); };
|
||||
|
||||
// Compile-only directory testing accepts the same four spellings. Its
|
||||
// final empty option may follow the package and restores the default.
|
||||
let testwork: str = strings.concat(root, "/test-work-", tags[si]);
|
||||
mkdirall(testwork);
|
||||
fi = 0;
|
||||
for (fi < forms.len) {
|
||||
let binary: str = strings.concat(outputs, "/test-", tags[si], "-",
|
||||
forms[fi], "=tail");
|
||||
let av: []str = [driver(stages[si]), "test", "-c", "-w", testwork,
|
||||
"-I", source];
|
||||
if (fi == 0) { append(av, "-o"); append(av, binary); }
|
||||
else if (fi == 1) { append(av, strings.concat("-o=", binary)); }
|
||||
else if (fi == 2) { append(av, "--o"); append(av, binary); }
|
||||
else { append(av, strings.concat("--o=", binary)); };
|
||||
append(av, tests);
|
||||
rewritefile(trace, "");
|
||||
runcommandenv(root, strings.concat("output-flag-test-", tags[si], "-",
|
||||
forms[fi]), av, env,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0
|
||||
&& os.exists(binary));
|
||||
if (fi == 0) { assert(readfile(trace).len != 0); }
|
||||
else { assert(readfile(trace).len == 0); };
|
||||
let bytes: str = readfile(binary);
|
||||
if (testref.len == 0) { testref = strings.dup(bytes); }
|
||||
else { assert(same(testref, bytes)); };
|
||||
let runav: []str = [binary];
|
||||
runcommand(root, strings.concat("output-flag-test-run-", tags[si], "-",
|
||||
forms[fi]), runav,
|
||||
(30i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stderr.len == 0 && has(out.stdout, "exact ... ok\n"));
|
||||
fi += 1;
|
||||
};
|
||||
let staletest: str = strings.concat(outputs, "/stale-test-", tags[si]);
|
||||
let runningretained: str = strings.concat(outputs,
|
||||
"/running-test-", tags[si], "=tail");
|
||||
let runningretainedav: []str = [driver(stages[si]), "test", "-w",
|
||||
testwork, "-I", source, strings.concat("--o=", runningretained),
|
||||
tests];
|
||||
rewritefile(trace, "");
|
||||
runcommandenvdir(root, strings.concat("output-flag-test-running-retained-",
|
||||
tags[si]), runningretainedav, env, root,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stderr.len == 0 && has(out.stdout, "exact ... ok\n")
|
||||
&& same(testref, readfile(runningretained))
|
||||
&& readfile(trace).len == 0);
|
||||
let defaulttest: str = strings.concat(root, "/tests.test");
|
||||
let testempty: []str = [driver(stages[si]), "test", "-c", "-w",
|
||||
testwork, "-I", source, "-o", staletest, tests, "--o", ""];
|
||||
rewritefile(trace, "");
|
||||
runcommandenvdir(root, strings.concat("output-flag-test-empty-", tags[si]),
|
||||
testempty, env, root,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0
|
||||
&& !os.exists(staletest) && same(testref, readfile(defaulttest))
|
||||
&& readfile(trace).len == 0
|
||||
&& !os.exists(strings.concat(root, "/=")));
|
||||
assert(os.remove(defaulttest) == 0);
|
||||
let runningstale: str = strings.concat(outputs,
|
||||
"/stale-running-test-", tags[si]);
|
||||
let runningempty: []str = [driver(stages[si]), "test", "-w",
|
||||
testwork, "-I", source, "-o", runningstale, tests, "-o="];
|
||||
rewritefile(trace, "");
|
||||
runcommandenvdir(root, strings.concat("output-flag-test-running-empty-",
|
||||
tags[si]), runningempty, env, root,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stderr.len == 0 && has(out.stdout, "exact ... ok\n")
|
||||
&& !os.exists(runningstale) && readfile(trace).len == 0);
|
||||
|
||||
// The raw single-file route owns output state in the public driver, so
|
||||
// final empty must normalize before its retain/copy decision too.
|
||||
let rawwork: str = strings.concat(root, "/raw-work-", tags[si]);
|
||||
mkdirall(rawwork);
|
||||
let rawretained: str = strings.concat(outputs, "/raw-test-", tags[si],
|
||||
"=tail");
|
||||
let rawretainedav: []str = [driver(stages[si]), "test", "-w", rawwork,
|
||||
strings.concat("--o=", rawretained), rawtest];
|
||||
runcommandenvdir(root, strings.concat("output-flag-raw-retained-",
|
||||
tags[si]), rawretainedav, env, root,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stderr.len == 0 && has(out.stdout, "raw_exact ... ok\n")
|
||||
&& os.exists(rawretained));
|
||||
let rawpublishedbytes: str = readfile(rawretained);
|
||||
if (rawref.len == 0) { rawref = strings.dup(rawpublishedbytes); }
|
||||
else { assert(same(rawref, rawpublishedbytes)); };
|
||||
let rawstale: str = strings.concat(outputs, "/stale-raw-", tags[si]);
|
||||
let rawempty: []str = [driver(stages[si]), "test", "-c", "-w",
|
||||
rawwork, "-o", rawstale, "--o=", rawtest];
|
||||
runcommandenvdir(root, strings.concat("output-flag-raw-empty-", tags[si]),
|
||||
rawempty, env, root,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
let rawbinary: str = strings.concat(rawwork, "/main");
|
||||
assert(out.stdout.len == 0 && out.stderr.len == 0
|
||||
&& !os.exists(rawstale) && os.exists(rawbinary)
|
||||
&& !os.exists(strings.concat(root, "/=")));
|
||||
let rawbytes: str = readfile(rawbinary);
|
||||
assert(same(rawref, rawbytes));
|
||||
ri = 0;
|
||||
for (ri < 2) {
|
||||
let badout: str = strings.concat(outputs, "/bad-test-", tags[si],
|
||||
"-", forms[ri]);
|
||||
let badwork: str = strings.concat(root, "/bad-test-work-", tags[si],
|
||||
"-", forms[ri]);
|
||||
let prefix: str = "-o";
|
||||
if (ri != 0) { prefix = "--o"; };
|
||||
let joined: str = strings.concat(prefix, badout);
|
||||
let badav: []str = [driver(stages[si]), "test", "-c", "-w",
|
||||
badwork, "-I", source, joined, tests];
|
||||
runcommand(root, strings.concat("output-flag-reject-test-", tags[si],
|
||||
"-", forms[ri]), badav, time.second, &out);
|
||||
expectexit(&out, 2);
|
||||
assert(out.stdout.len == 0
|
||||
&& same(out.stderr, "ww test: unknown flag\n")
|
||||
&& !os.exists(badout) && !os.exists(badwork));
|
||||
if (si == 0) { rejectrefs[2 + ri] = strings.dup(out.stderr); }
|
||||
else { assert(same(rejectrefs[2 + ri], out.stderr)); };
|
||||
ri += 1;
|
||||
};
|
||||
let testmissingwork: str = strings.concat(root,
|
||||
"/missing-test-work-", tags[si]);
|
||||
let testmissing: []str = [driver(stages[si]), "test", "-c", "-w",
|
||||
testmissingwork, "-I", source, "--o"];
|
||||
runcommand(root, strings.concat("output-flag-missing-test-", tags[si]),
|
||||
testmissing, time.second, &out);
|
||||
expectexit(&out, 2);
|
||||
assert(out.stdout.len == 0
|
||||
&& same(out.stderr, "ww test: -o needs an argument\n")
|
||||
&& !os.exists(testmissingwork));
|
||||
if (si == 0) { testmissingref = strings.dup(out.stderr); }
|
||||
else { assert(same(testmissingref, out.stderr)); };
|
||||
|
||||
let cleanpaths: []str = [root, outputs, source, multi_a, multi_b, tests,
|
||||
buildwork, multiwork, testwork, rawwork];
|
||||
let ci: i32 = 0;
|
||||
for (ci < cleanpaths.len) {
|
||||
assert(!directoryhasnew(cleanpaths[ci])
|
||||
&& !directoryhasfragment(cleanpaths[ci], ".install")
|
||||
&& !directoryhasfragment(cleanpaths[ci], ".wwtxn."));
|
||||
ci += 1;
|
||||
};
|
||||
si += 1;
|
||||
};
|
||||
assert(!os.exists(strings.concat(root, "/="))
|
||||
&& !os.exists(strings.concat(root, "/=.sepwork")));
|
||||
clean(root);
|
||||
};
|
||||
|
||||
@test fn compile_artifact_naming() void = {
|
||||
let root: str = fresh();
|
||||
let pdir: str = strings.concat(root, "/pkg");
|
||||
|
||||
Reference in New Issue
Block a user