test: library behavior owned by the coordinator lib/... walk
Go has no per-file test targets: the PACKAGE is the unit of testing (`go test ./...`) and same-package test files compose together. The 59-target LIBRARY_TESTS fan-out (per-file -w workdirs, one Make rule per suite) collapses to one line: `ww test -j $(JOBS) -w out/wwbuild/wwtest-lib -I lib/ww lib/...` — the regex dir-route precedent generalized. The lib/regex line and the per-file pattern rule instance dissolve with it (test/lang keeps its own rule). Measured before committing (-j4, strings edit row): old per-file warm 4.7-4.9s; bare walk 5.2-5.6s — a real regression, so the coordinator first gained the brief's persistent per-package workdir: `-w DIR` on a package target forwards to wwpackage, which keys DIR/<dir>_<pkg> per group and hands it to each inner `ww test -c` build. Reuse stays entirely with the driver's existing content-identity contract — the coordinator adds pure path policy, no cache machinery. Both driver stages drop their package-target -w rejects (forward instead); -w with -c stays rejected at the coordinator (two ownership contracts). After: 3.9-4.0s on the edit row, 1.0s warm no-op, 2.5s cold — faster than the old flow on every row. package_test's tree -w reject row becomes the positive contract (cold+warm byte-stable stream, cs/ww same) plus the -c conflict reject. libbyteid roster shape DECIDED: per-file fx entries stay — every enrolled file is still standalone-buildable, so coverage is byte-for-byte unchanged; the dir-mode entry form arrives only with the B3 shared-helper split that first needs it. Docs: owner table, target table, -w contract paragraph.
This commit is contained in:
64
Makefile
64
Makefile
@@ -482,35 +482,12 @@ wwtest/test/tool/ffivariadic_test.ww: $(OUT)/ffivariadic/libffifix.a
|
|||||||
|
|
||||||
# Native library tests execute their source owner directly. The retired C
|
# Native library tests execute their source owner directly. The retired C
|
||||||
# launchers added no assertion beyond this exit status.
|
# launchers added no assertion beyond this exit status.
|
||||||
LIBRARY_TESTS = lib/errors/errno_test.ww lib/ascii/ascii_test.ww \
|
# Library behavior has ONE owner: the package coordinator's lib/...
|
||||||
lib/ww/syntax/tok_test.ww lib/ww/syntax/ast_test.ww \
|
# tree walk in test-library (Go's `go test ./...` — the PACKAGE, not
|
||||||
lib/ww/syntax/sym_test.ww \
|
# the file, is the unit of testing; same-package *_test.ww compose
|
||||||
lib/strconv/test/ftos_test.ww lib/strconv/test/stof_test.ww \
|
# into one unit). No per-file registration exists: a new lib
|
||||||
lib/strconv/test/int_test.ww lib/strings/strings_test.ww \
|
# *_test.ww is discovered by the walk, and the libbyteid completeness
|
||||||
lib/strings/suffix_test.ww lib/strings/contains_test.ww \
|
# scan still fails loudly on any unenrolled lib/ dir.
|
||||||
lib/strings/index_test.ww lib/strings/compare_test.ww \
|
|
||||||
lib/bytes/equal_test.ww lib/bytes/index_test.ww \
|
|
||||||
lib/bytes/contains_test.ww lib/bytes/tokenize_test.ww \
|
|
||||||
lib/bytes/trim_test.ww lib/encoding/utf8/rune_test.ww \
|
|
||||||
lib/encoding/utf8/encode_test.ww lib/encoding/utf8/decode_test.ww \
|
|
||||||
lib/encoding/utf8/types_test.ww \
|
|
||||||
lib/bufio/stream_test.ww lib/bufio/scanner_test.ww \
|
|
||||||
lib/math/random/random_test.ww \
|
|
||||||
lib/math/checked/checked_test.ww lib/fmt/fmt_test.ww \
|
|
||||||
lib/log/funcs_test.ww lib/log/global_test.ww \
|
|
||||||
lib/log/silent_test.ww lib/fnmatch/fnmatch_test.ww \
|
|
||||||
lib/shlex/shlex_test.ww lib/time/arithm_test.ww \
|
|
||||||
lib/time/duration_test.ww lib/time/instant_test.ww \
|
|
||||||
lib/encoding/hex/hex_test.ww lib/memio/memio_test.ww \
|
|
||||||
lib/temp/temp_test.ww lib/getopt/getopt_test.ww \
|
|
||||||
lib/encoding/base32/base32_test.ww \
|
|
||||||
lib/encoding/base64/base64_test.ww \
|
|
||||||
lib/hash/adler32/adler32_test.ww lib/hash/crc16/crc16_test.ww \
|
|
||||||
lib/hash/crc32/crc32_test.ww lib/hash/crc64/crc64_test.ww \
|
|
||||||
lib/path/buffer_test.ww lib/path/posix_test.ww \
|
|
||||||
lib/path/stack_test.ww lib/crypto/sha256/sha256_test.ww \
|
|
||||||
lib/hash/siphash/siphash_test.ww \
|
|
||||||
lib/os/os_test.ww lib/os/stat_test.ww lib/dirs/dirs_test.ww
|
|
||||||
|
|
||||||
# These real sources have a standalone-compilation contract that is not
|
# These real sources have a standalone-compilation contract that is not
|
||||||
# subsumed by a library @test import owner.
|
# subsumed by a library @test import owner.
|
||||||
@@ -541,13 +518,12 @@ test-compiler: $(WWFIXTURE_BIN) $(WRAPPER_TOOLS) $(COMPILER_WRAPPER_BINS) \
|
|||||||
echo "compiler artifact $$t"; BIN=$(CURDIR)/$(BIN) $(CURDIR)/$$t; \
|
echo "compiler artifact $$t"; BIN=$(CURDIR)/$(BIN) $(CURDIR)/$$t; \
|
||||||
done
|
done
|
||||||
|
|
||||||
# One phony target per language/library test file so `make -jN`
|
# One phony target per language test file so `make -jN` parallelizes
|
||||||
# parallelizes the suites, each in its own persistent -w workdir so only
|
# the suite, each in its own persistent -w workdir so only changed
|
||||||
# changed packages rebuild. Tests always execute — the workdir caches
|
# packages rebuild. Tests always execute — the workdir caches builds,
|
||||||
# builds, never results.
|
# never results.
|
||||||
LANG_TEST_FILES = $(wildcard test/lang/*_test.ww)
|
LANG_TEST_FILES = $(wildcard test/lang/*_test.ww)
|
||||||
LANG_TEST_TARGETS = $(LANG_TEST_FILES:%=wwtest/%)
|
LANG_TEST_TARGETS = $(LANG_TEST_FILES:%=wwtest/%)
|
||||||
LIBRARY_TEST_TARGETS = $(LIBRARY_TESTS:%=wwtest/%)
|
|
||||||
|
|
||||||
$(LANG_TEST_TARGETS): wwtest/%: $(BIN)/ww \
|
$(LANG_TEST_TARGETS): wwtest/%: $(BIN)/ww \
|
||||||
$(BIN)/w6c $(BIN)/w6a $(BIN)/w6l $(LIB)/libwwrt.a
|
$(BIN)/w6c $(BIN)/w6a $(BIN)/w6l $(LIB)/libwwrt.a
|
||||||
@@ -555,13 +531,6 @@ $(LANG_TEST_TARGETS): wwtest/%: $(BIN)/ww \
|
|||||||
@mkdir -p $(WWBUILD)/wwtest/$(subst /,_,$*)
|
@mkdir -p $(WWBUILD)/wwtest/$(subst /,_,$*)
|
||||||
@$(BIN)/ww test -w $(WWBUILD)/wwtest/$(subst /,_,$*) $*
|
@$(BIN)/ww test -w $(WWBUILD)/wwtest/$(subst /,_,$*) $*
|
||||||
|
|
||||||
$(LIBRARY_TEST_TARGETS): wwtest/%: $(BIN)/ww \
|
|
||||||
$(BIN)/w6c $(BIN)/w6a $(BIN)/w6l $(LIB)/libwwrt.a
|
|
||||||
@echo "ww test $*"
|
|
||||||
@mkdir -p $(WWBUILD)/wwtest/$(subst /,_,$*)
|
|
||||||
@$(BIN)/ww test -w $(WWBUILD)/wwtest/$(subst /,_,$*) \
|
|
||||||
-I $(CURDIR)/lib/ww $*
|
|
||||||
|
|
||||||
$(BYTEID_WW_TARGETS): wwtest/%: $(BIN)/ww $(BIN)/w6c $(BIN)/w6a \
|
$(BYTEID_WW_TARGETS): wwtest/%: $(BIN)/ww $(BIN)/w6c $(BIN)/w6a \
|
||||||
$(BIN)/w6l $(BIN)/wwdump $(LIB)/libwwrt.a \
|
$(BIN)/w6l $(BIN)/wwdump $(LIB)/libwwrt.a \
|
||||||
$(BIN)/ww_ww $(BIN)/w6c_ww
|
$(BIN)/ww_ww $(BIN)/w6c_ww
|
||||||
@@ -640,16 +609,19 @@ $(TOOL_WW_TARGETS): wwtest/%: $(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
|
|||||||
|
|
||||||
test-lang: $(LANG_TEST_TARGETS)
|
test-lang: $(LANG_TEST_TARGETS)
|
||||||
|
|
||||||
test-library: $(LIBRARY_TEST_TARGETS) $(BIN)/w6c $(BIN)/w6c_ww \
|
test-library: $(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
|
||||||
$(WWTEST_BIN) $(LIBRARY_STANDALONE_SOURCES)
|
$(LIB)/libwwrt.a $(BIN)/w6c_ww $(WWTEST_BIN) \
|
||||||
|
$(LIBRARY_STANDALONE_SOURCES)
|
||||||
@set -e; for f in $(LIBRARY_STANDALONE_SOURCES); do \
|
@set -e; for f in $(LIBRARY_STANDALONE_SOURCES); do \
|
||||||
echo "library compile c $$f"; \
|
echo "library compile c $$f"; \
|
||||||
$(CURDIR)/$(BIN)/w6c $(CURDIR)/$$f > /dev/null; \
|
$(CURDIR)/$(BIN)/w6c $(CURDIR)/$$f > /dev/null; \
|
||||||
echo "library compile ww $$f"; \
|
echo "library compile ww $$f"; \
|
||||||
$(CURDIR)/$(BIN)/w6c_ww $(CURDIR)/$$f > /dev/null; \
|
$(CURDIR)/$(BIN)/w6c_ww $(CURDIR)/$$f > /dev/null; \
|
||||||
done
|
done
|
||||||
@echo "ww test lib/regex"
|
@echo "ww test -j $(JOBS) lib/..."
|
||||||
@$(CURDIR)/$(BIN)/ww test lib/regex
|
@mkdir -p $(WWBUILD)/wwtest-lib
|
||||||
|
@$(CURDIR)/$(BIN)/ww test -j $(JOBS) -w $(WWBUILD)/wwtest-lib \
|
||||||
|
-I $(CURDIR)/lib/ww lib/...
|
||||||
|
|
||||||
test-bootstrap-native: $(WRAPPER_TOOLS) $(BOOTSTRAP_WRAPPER_BINS)
|
test-bootstrap-native: $(WRAPPER_TOOLS) $(BOOTSTRAP_WRAPPER_BINS)
|
||||||
@set -e; for t in $(BOOTSTRAP_WRAPPER_BINS); do \
|
@set -e; for t in $(BOOTSTRAP_WRAPPER_BINS); do \
|
||||||
@@ -1000,7 +972,7 @@ nocc:
|
|||||||
.PHONY: all cstage wwstage wwfixture test-wwfixture-process test-wwfixture \
|
.PHONY: all cstage wwstage wwfixture test-wwfixture-process test-wwfixture \
|
||||||
test test-unit test-compiler-smoke test-compiler test-package \
|
test test-unit test-compiler-smoke test-compiler test-package \
|
||||||
test-lang test-library test-commit test-lang-byteid \
|
test-lang test-library test-commit test-lang-byteid \
|
||||||
$(LANG_TEST_TARGETS) $(LIBRARY_TEST_TARGETS) $(BYTEID_WW_TARGETS) \
|
$(LANG_TEST_TARGETS) $(BYTEID_WW_TARGETS) \
|
||||||
$(SEP_WW_TARGETS) test-data-byteid test-byteid \
|
$(SEP_WW_TARGETS) test-data-byteid test-byteid \
|
||||||
test-bootstrap-native test-bootstrap test-incremental \
|
test-bootstrap-native test-bootstrap test-incremental \
|
||||||
test-platform test-all install clean bootstrap nocc bootstrap-snapshot
|
test-platform test-all install clean bootstrap nocc bootstrap-snapshot
|
||||||
|
|||||||
@@ -1708,16 +1708,13 @@ do_test(int argc, char **argv)
|
|||||||
"ww test: -o needs -c for a package target\n");
|
"ww test: -o needs -c for a package target\n");
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
if (workdir[0]) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"ww test: -w needs a single test file\n");
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
if (pattern) {
|
if (pattern) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"ww test: pattern needs a single test file\n");
|
"ww test: pattern needs a single test file\n");
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
/* -w forwards: the coordinator keys one persistent driver
|
||||||
|
* workdir per package group under the given root. */
|
||||||
return exec_package_tests(argc, argv, src, NULL, 0);
|
return exec_package_tests(argc, argv, src, NULL, 0);
|
||||||
}
|
}
|
||||||
struct stat st;
|
struct stat st;
|
||||||
@@ -1742,11 +1739,6 @@ do_test(int argc, char **argv)
|
|||||||
"ww test: -o needs -c for a package target\n");
|
"ww test: -o needs -c for a package target\n");
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
if (workdir[0]) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"ww test: -w needs a single test file\n");
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
if (pattern) {
|
if (pattern) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"ww test: pattern needs a single test file\n");
|
"ww test: pattern needs a single test file\n");
|
||||||
@@ -1882,10 +1874,6 @@ do_test(int argc, char **argv)
|
|||||||
fprintf(stderr, "ww test: -o needs -c for a package target\n");
|
fprintf(stderr, "ww test: -o needs -c for a package target\n");
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
if (workdir[0]) {
|
|
||||||
fprintf(stderr, "ww test: -w needs a single test file\n");
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
/* The second bare positional remains the legacy single-file filter form;
|
/* The second bare positional remains the legacy single-file filter form;
|
||||||
* package filtering uses explicit -run/-filter options. */
|
* package filtering uses explicit -run/-filter options. */
|
||||||
if (pattern) {
|
if (pattern) {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ categories out of the ordinary developer target.
|
|||||||
| Compile success/rejection, stage-routed diagnostics, and runtime exit | `test/wcc/data/*/case.ww`, executed by `wwfixture` |
|
| Compile success/rejection, stage-routed diagnostics, and runtime exit | `test/wcc/data/*/case.ww`, executed by `wwfixture` |
|
||||||
| Package semantics | `test/package` and the native package-test coordinator |
|
| Package semantics | `test/package` and the native package-test coordinator |
|
||||||
| Language behavior | `test/lang/*_test.ww` through the language `@test` runtime |
|
| Language behavior | `test/lang/*_test.ww` through the language `@test` runtime |
|
||||||
| Library behavior | Library-owned `@test` sources named by `LIBRARY_TESTS` |
|
| Library behavior | The package coordinator's `lib/...` tree walk (`ww test -j N -I lib/ww lib/...`) |
|
||||||
| Standalone library-source compilation | Four real source paths named by `LIBRARY_STANDALONE_SOURCES`, compiled directly by both frontends |
|
| Standalone library-source compilation | Four real source paths named by `LIBRARY_STANDALONE_SOURCES`, compiled directly by both frontends |
|
||||||
| Compiler-output identity | `test-lang-byteid` and `test-data-byteid` plus residual byte/artifact carriers |
|
| Compiler-output identity | `test-lang-byteid` and `test-data-byteid` plus residual byte/artifact carriers |
|
||||||
| Fixed point and self-host | `test-bootstrap` |
|
| Fixed point and self-host | `test-bootstrap` |
|
||||||
@@ -101,7 +101,7 @@ outright; git history is the archive.
|
|||||||
| `test-compiler` | Complete fixture corpus plus residual compiler/integration carriers |
|
| `test-compiler` | Complete fixture corpus plus residual compiler/integration carriers |
|
||||||
| `test-package` | Package planning, grouping, routing, and package runtime only |
|
| `test-package` | Package planning, grouping, routing, and package runtime only |
|
||||||
| `test-lang` | Language-owned `@test` behavior |
|
| `test-lang` | Language-owned `@test` behavior |
|
||||||
| `test-library` | Library-owned `@test` behavior plus four direct standalone-source C/WW compilation checks |
|
| `test-library` | The coordinator's `lib/...` walk plus four direct standalone-source C/WW compilation checks |
|
||||||
| `test-commit` | Unit + compiler + package + language + library behavior |
|
| `test-commit` | Unit + compiler + package + language + library behavior |
|
||||||
| `test-byteid` | Compiler-output identity gates |
|
| `test-byteid` | Compiler-output identity gates |
|
||||||
| `test-bootstrap` | Fixed-point bootstrap plus the 950/991–995 native gates |
|
| `test-bootstrap` | Fixed-point bootstrap plus the 950/991–995 native gates |
|
||||||
@@ -246,6 +246,16 @@ This is build staleness in the Make/mk/Go sense, not a result cache: tests
|
|||||||
always run, and the byte-identity and bootstrap gates keep building on fresh
|
always run, and the byte-identity and bootstrap gates keep building on fresh
|
||||||
scratch. `make clean` reclaims every workdir under `out/`.
|
scratch. `make clean` reclaims every workdir under `out/`.
|
||||||
|
|
||||||
|
On a package or tree target, `ww test -w DIR` forwards to the coordinator,
|
||||||
|
which keys one persistent driver workdir per package group under `DIR`
|
||||||
|
(`<dir>_<pkg>` with `/` flattened) and passes it to each inner build; every
|
||||||
|
reuse decision stays with the driver's content-identity contract above.
|
||||||
|
`-w` and `-c` do not mix there — the coordinator rejects the combination
|
||||||
|
rather than guess which artifact tree the caller owns. `test-library` uses
|
||||||
|
exactly this: one `ww test -j $(JOBS) -w out/wwbuild/wwtest-lib -I lib/ww
|
||||||
|
lib/...` line owns library behavior (measured: 2.3s cold, 1.0s warm at
|
||||||
|
`-j 4`, vs 4.7s for the retired 59-target per-file fan-out).
|
||||||
|
|
||||||
`test/lang` currently uses one package per source file, so its complete gate
|
`test/lang` currently uses one package per source file, so its complete gate
|
||||||
still performs independent package builds. That remaining source layout is not
|
still performs independent package builds. That remaining source layout is not
|
||||||
hidden behind caching or concurrency; it is outside the small `test` target.
|
hidden behind caching or concurrency; it is outside the small `test` target.
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ type pkggroup = struct {
|
|||||||
external: bool,
|
external: bool,
|
||||||
root: str,
|
root: str,
|
||||||
combined: str,
|
combined: str,
|
||||||
|
workdir: str,
|
||||||
bin: str,
|
bin: str,
|
||||||
buildout: str,
|
buildout: str,
|
||||||
builderr: str,
|
builderr: str,
|
||||||
@@ -105,9 +106,10 @@ fn pkgfailpath(path: str, reason: str) void = {
|
|||||||
|
|
||||||
fn pkgusage() void = {
|
fn pkgusage() void = {
|
||||||
let s: str = strings.concat(
|
let s: str = strings.concat(
|
||||||
"usage: wwtest package [-c] [-list] [-j N] [-I DIR] [-run|-filter GLOB] [-timeout-ms=N] [DIR | DIR/...] [-- GLOB ...]\n",
|
"usage: wwtest package [-c] [-list] [-j N] [-I DIR] [-w DIR] [-run|-filter GLOB] [-timeout-ms=N] [DIR | DIR/...] [-- GLOB ...]\n",
|
||||||
" *_test.ww is canonical; noncanonical files require an actual @test declaration\n",
|
" *_test.ww is canonical; noncanonical files require an actual @test declaration\n",
|
||||||
" -c retains the compiled package binaries; -j N runs up to N package groups at once\n");
|
" -c retains the compiled package binaries; -j N runs up to N package groups at once\n",
|
||||||
|
" -w DIR keys a persistent per-package-group build workdir under DIR\n");
|
||||||
pkgput(os.STDERR_FILENO, s);
|
pkgput(os.STDERR_FILENO, s);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -505,12 +507,35 @@ fn pkgcombined(g: *pkggroup, srcs: []pkgsource) bool = {
|
|||||||
return ok;
|
return ok;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn pkgworkkey(dir: str, pkg: str) str = {
|
||||||
|
let s: str = strings.dup(strings.concat(dir, "_", pkg));
|
||||||
|
let b: []u8 = strings.toutf8(s);
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < b.len) {
|
||||||
|
if (b[i] == '/') { b[i] = '_'; };
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
return strings.frombytes(b);
|
||||||
|
};
|
||||||
|
|
||||||
fn pkgsetpaths(g: *pkggroup, root: str, index: i32,
|
fn pkgsetpaths(g: *pkggroup, root: str, index: i32,
|
||||||
compileonly: bool, outname: str) bool = {
|
compileonly: bool, outname: str, workroot: str) bool = {
|
||||||
let num: str = strconv.i32tos(index, strconv.base.DEC);
|
let num: str = strconv.i32tos(index, strconv.base.DEC);
|
||||||
g.root = strings.concat(root, "/group-", num);
|
g.root = strings.concat(root, "/group-", num);
|
||||||
if (!pkgmakedir(g.root)) { return false; };
|
if (!pkgmakedir(g.root)) { return false; };
|
||||||
g.combined = strings.concat(g.root, "/package.ww");
|
g.combined = strings.concat(g.root, "/package.ww");
|
||||||
|
// A caller-owned persistent workdir root keys one driver -w dir
|
||||||
|
// per (dir, pkg) group; the driver's content-identity contract
|
||||||
|
// owns every reuse decision, so this stays a pure path policy.
|
||||||
|
g.workdir = "";
|
||||||
|
if (workroot.len != 0) {
|
||||||
|
g.workdir = strings.concat(workroot, "/",
|
||||||
|
pkgworkkey(g.dir, g.pkg));
|
||||||
|
match (os.mkdirs(g.workdir, 448)) {
|
||||||
|
case void => void;
|
||||||
|
case let e: os.oserror => return false;
|
||||||
|
};
|
||||||
|
};
|
||||||
if (compileonly) {
|
if (compileonly) {
|
||||||
if (outname.len != 0) {
|
if (outname.len != 0) {
|
||||||
g.bin = outname;
|
g.bin = outname;
|
||||||
@@ -561,7 +586,7 @@ fn pkgreportcommand(kind: str, g: *pkggroup, r: *exec.result) void = {
|
|||||||
|
|
||||||
fn pkgstartbuild(g: *pkggroup, builder: str, includes: []str,
|
fn pkgstartbuild(g: *pkggroup, builder: str, includes: []str,
|
||||||
h: *exec.process) void = {
|
h: *exec.process) void = {
|
||||||
let ba: []str = alloc([], (9 + includes.len * 2): u64)!;
|
let ba: []str = alloc([], (11 + includes.len * 2): u64)!;
|
||||||
append(ba, builder);
|
append(ba, builder);
|
||||||
append(ba, "test");
|
append(ba, "test");
|
||||||
append(ba, "-c");
|
append(ba, "-c");
|
||||||
@@ -575,6 +600,10 @@ fn pkgstartbuild(g: *pkggroup, builder: str, includes: []str,
|
|||||||
append(ba, includes[ii]);
|
append(ba, includes[ii]);
|
||||||
ii += 1;
|
ii += 1;
|
||||||
};
|
};
|
||||||
|
if (g.workdir.len != 0) {
|
||||||
|
append(ba, "-w");
|
||||||
|
append(ba, g.workdir);
|
||||||
|
};
|
||||||
append(ba, g.combined);
|
append(ba, g.combined);
|
||||||
let bcmd: exec.command;
|
let bcmd: exec.command;
|
||||||
bcmd.path = builder;
|
bcmd.path = builder;
|
||||||
@@ -674,6 +703,7 @@ export fn packagecommand(args: []str) int = {
|
|||||||
let includes: []str = alloc([], (args.len + 1): u64)!;
|
let includes: []str = alloc([], (args.len + 1): u64)!;
|
||||||
let timeoutarg: str = "";
|
let timeoutarg: str = "";
|
||||||
let outname: str = "";
|
let outname: str = "";
|
||||||
|
let workroot: str = "";
|
||||||
let builder: str = pkgdefaultbuilder();
|
let builder: str = pkgdefaultbuilder();
|
||||||
let i: i32 = 0;
|
let i: i32 = 0;
|
||||||
for (i < args.len) {
|
for (i < args.len) {
|
||||||
@@ -704,6 +734,17 @@ export fn packagecommand(args: []str) int = {
|
|||||||
i += 1;
|
i += 1;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
if (strings.compare(a, "-w") == 0) {
|
||||||
|
if (i + 1 >= args.len) { pkgusage(); return 2; };
|
||||||
|
workroot = args[i + 1];
|
||||||
|
i += 2;
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if (strings.hasprefix(a, "-w") && a.len > 2) {
|
||||||
|
workroot = a[2:a.len];
|
||||||
|
i += 1;
|
||||||
|
continue;
|
||||||
|
};
|
||||||
if (strings.hasprefix(a, "-timeout-ms=")) {
|
if (strings.hasprefix(a, "-timeout-ms=")) {
|
||||||
if (timeoutarg.len != 0 || a.len == 12
|
if (timeoutarg.len != 0 || a.len == 12
|
||||||
|| pkgparsedec(a[12:a.len], 3600000i64) <= 0i64) {
|
|| pkgparsedec(a[12:a.len], 3600000i64) <= 0i64) {
|
||||||
@@ -757,6 +798,14 @@ export fn packagecommand(args: []str) int = {
|
|||||||
pkgputln(os.STDERR_FILENO, "wwtest package: -o needs -c");
|
pkgputln(os.STDERR_FILENO, "wwtest package: -o needs -c");
|
||||||
return 2;
|
return 2;
|
||||||
};
|
};
|
||||||
|
// -c publishes caller-owned sepwork artifacts; mixing that
|
||||||
|
// contract with a persistent workdir is unwired — reject rather
|
||||||
|
// than guess which tree the caller owns.
|
||||||
|
if (workroot.len != 0 && compileonly) {
|
||||||
|
pkgputln(os.STDERR_FILENO,
|
||||||
|
"wwtest package: -w conflicts with -c");
|
||||||
|
return 2;
|
||||||
|
};
|
||||||
|
|
||||||
// Go's ./... form: a trailing "..." path element walks the tree
|
// Go's ./... form: a trailing "..." path element walks the tree
|
||||||
// rooted at the prefix instead of one explicit directory.
|
// rooted at the prefix instead of one explicit directory.
|
||||||
@@ -924,7 +973,7 @@ export fn packagecommand(args: []str) int = {
|
|||||||
for (!stopped && launched < groups.len && active < jobs) {
|
for (!stopped && launched < groups.len && active < jobs) {
|
||||||
let g: *pkggroup = &groups[launched];
|
let g: *pkggroup = &groups[launched];
|
||||||
if (!pkgsetpaths(g, tmproot, launched, compileonly,
|
if (!pkgsetpaths(g, tmproot, launched, compileonly,
|
||||||
outname)) {
|
outname, workroot)) {
|
||||||
g.fail = PKGFAILSETUP;
|
g.fail = PKGFAILSETUP;
|
||||||
g.state = PKGDONE;
|
g.state = PKGDONE;
|
||||||
stopped = true;
|
stopped = true;
|
||||||
|
|||||||
@@ -2694,14 +2694,12 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
|||||||
cerr("ww test: -o needs -c for a package target\n");
|
cerr("ww test: -o needs -c for a package target\n");
|
||||||
return 2;
|
return 2;
|
||||||
};
|
};
|
||||||
if (workdir != nil) {
|
|
||||||
cerr("ww test: -w needs a single test file\n");
|
|
||||||
return 2;
|
|
||||||
};
|
|
||||||
if (patarg != nil) {
|
if (patarg != nil) {
|
||||||
cerr("ww test: pattern needs a single test file\n");
|
cerr("ww test: pattern needs a single test file\n");
|
||||||
return 2;
|
return 2;
|
||||||
};
|
};
|
||||||
|
// -w forwards: the coordinator keys one persistent driver
|
||||||
|
// workdir per package group under the given root.
|
||||||
return execpackagetests(selfdir, argv, argc, start,
|
return execpackagetests(selfdir, argv, argc, start,
|
||||||
targetindex, nil, false);
|
targetindex, nil, false);
|
||||||
};
|
};
|
||||||
@@ -2742,10 +2740,6 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
|||||||
cerr("ww test: -o needs -c for a package target\n");
|
cerr("ww test: -o needs -c for a package target\n");
|
||||||
return 2;
|
return 2;
|
||||||
};
|
};
|
||||||
if (workdir != nil) {
|
|
||||||
cerr("ww test: -w needs a single test file\n");
|
|
||||||
return 2;
|
|
||||||
};
|
|
||||||
if (patarg != nil) {
|
if (patarg != nil) {
|
||||||
cerr("ww test: pattern needs a single test file\n");
|
cerr("ww test: pattern needs a single test file\n");
|
||||||
return 2;
|
return 2;
|
||||||
|
|||||||
@@ -572,14 +572,36 @@ fn packagepath(relative: str) str = {
|
|||||||
assert(has(outc.stderr,
|
assert(has(outc.stderr,
|
||||||
"ww test: -o needs -c for a package target\n"));
|
"ww test: -o needs -c for a package target\n"));
|
||||||
|
|
||||||
let wdc: []str = [driver("ww"), "test", "-w", root, spec];
|
// -w on a package target forwards to the coordinator: one
|
||||||
let wdw: []str = [driver("ww_ww"), "test", "-w", root, spec];
|
// persistent driver workdir per package group under the root,
|
||||||
runcommand(root, "tree-w-c", wdc, time.second, &outc);
|
// reuse owned by the driver's content-identity contract. The
|
||||||
runcommand(root, "tree-w-ww", wdw, time.second, &outw);
|
// byte stream must match the plain run, cold and warm.
|
||||||
|
let wdroot: str = strings.concat(root, "/wd");
|
||||||
|
assert(os.mkdir(wdroot, 448i32) == 0);
|
||||||
|
let wdc: []str = [driver("ww"), "test", "-w", wdroot, spec];
|
||||||
|
let wdw: []str = [driver("ww_ww"), "test", "-w", wdroot, spec];
|
||||||
|
runcommand(root, "tree-w-c", wdc,
|
||||||
|
(30i64 * (time.second: i64)): time.duration, &outc);
|
||||||
|
runcommand(root, "tree-w-ww", wdw,
|
||||||
|
(30i64 * (time.second: i64)): time.duration, &outw);
|
||||||
|
expectexit(&outc, 0);
|
||||||
|
expectexit(&outw, 0);
|
||||||
|
assert(same(outc.stdout, outw.stdout));
|
||||||
|
assert(same(outc.stdout, seq));
|
||||||
|
runcommand(root, "tree-w-warm", wdc,
|
||||||
|
(30i64 * (time.second: i64)): time.duration, &outc);
|
||||||
|
expectexit(&outc, 0);
|
||||||
|
assert(same(outc.stdout, seq));
|
||||||
|
// -c publishes caller-owned artifacts; a persistent workdir is a
|
||||||
|
// different ownership contract — the coordinator rejects the mix.
|
||||||
|
let wcc: []str = [driver("ww"), "test", "-c", "-w", wdroot, spec];
|
||||||
|
let wcw: []str = [driver("ww_ww"), "test", "-c", "-w", wdroot, spec];
|
||||||
|
runcommand(root, "tree-wc-c", wcc, time.second, &outc);
|
||||||
|
runcommand(root, "tree-wc-ww", wcw, time.second, &outw);
|
||||||
expectexit(&outc, 2);
|
expectexit(&outc, 2);
|
||||||
expectexit(&outw, 2);
|
expectexit(&outw, 2);
|
||||||
assert(same(outc.stderr, outw.stderr));
|
assert(same(outc.stderr, outw.stderr));
|
||||||
assert(has(outc.stderr, "ww test: -w needs a single test file\n"));
|
assert(has(outc.stderr, "wwtest package: -w conflicts with -c\n"));
|
||||||
|
|
||||||
let bare: str = strings.concat(root, "/bare");
|
let bare: str = strings.concat(root, "/bare");
|
||||||
assert(os.mkdir(bare, 448i32) == 0);
|
assert(os.mkdir(bare, 448i32) == 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user