ww: implement recursive local package patterns
This commit is contained in:
3
Makefile
3
Makefile
@@ -53,7 +53,8 @@ RT_OBJ = $(RT_S:rt/%.s=$(OBJ)/rt/%.o) $(RT_WW:rt/%.ww=$(OBJ)/rt/%.o)
|
||||
|
||||
WWTEST_BIN = $(BIN)/wwtest
|
||||
WWTEST_SRC = cmd/wwtest/wwtest.ww \
|
||||
internal/wwpackage/package.ww lib/os/exec/exec.ww \
|
||||
internal/wwpackage/package.ww internal/wwpackage/isprint.ww \
|
||||
lib/os/exec/exec.ww \
|
||||
lib/ascii/ascii.ww lib/bytes/bytes.ww \
|
||||
lib/crypto/math/math.ww lib/crypto/sha256/sha256.ww \
|
||||
lib/endian/big.ww lib/endian/little.ww lib/endian/network.ww \
|
||||
|
||||
429
cmd/ww/main.c
429
cmd/ww/main.c
@@ -24,9 +24,9 @@
|
||||
static const char *usage =
|
||||
"usage: ww [-V] <subcommand> [args...]\n"
|
||||
" -V print version and exit\n"
|
||||
" build [-S] [-w DIR] [-I DIR] [-o FILE] [path] build a local package graph\n"
|
||||
" build [-S] [-w DIR] [-I DIR] [-o FILE] [path ...] build local package graphs\n"
|
||||
" run [path] ... build then exec, passing extra args to the program\n"
|
||||
" test [-S -o STEM] [-w DIR] [options] [path] build/run tests; -S emits package asm\n"
|
||||
" test [-S -o STEM] [-w DIR] [options] [path ...] build/run tests; -S emits package asm\n"
|
||||
" version print version and exit\n"
|
||||
"\n"
|
||||
" path forms:\n"
|
||||
@@ -34,13 +34,14 @@ static const char *usage =
|
||||
" foo search cwd, -I dirs, then the source library for foo.ww or foo/\n"
|
||||
" lib/foo directory: build its package sources\n"
|
||||
" -o publishes a non-main archive FILE + FILE.wwi\n"
|
||||
" lib/... every package under lib, recursively (test only)\n"
|
||||
" lib/... every eligible package under lib, recursively\n"
|
||||
" . build the cwd's <basename>.ww\n";
|
||||
|
||||
static char *self_dir;
|
||||
static const char *self_path;
|
||||
static char *sep_sprintf(const char *, ...);
|
||||
static int sep_reserve(void **, int *, int, size_t);
|
||||
static int sep_fail_size(void);
|
||||
|
||||
static const char *
|
||||
envpath(const char *name)
|
||||
@@ -115,28 +116,38 @@ run_test_bin(const char *bin, const char *pattern)
|
||||
* package root through `ww test -c ... package.ww`, so that file boundary also
|
||||
* prevents delegation recursion. */
|
||||
static int
|
||||
exec_package_tests(int argc, char **argv, const char *target,
|
||||
const char *resolved, const char *root_identity, int add_dot)
|
||||
exec_package_command(int argc, char **argv, const char *target,
|
||||
const char *resolved, const char *root_identity, int add_dot,
|
||||
int build_only)
|
||||
{
|
||||
const char *override = getenv("WW_WWTEST");
|
||||
char fallback[PATH_MAX];
|
||||
const char *prog = override && override[0] ? override : fallback;
|
||||
if (prog == fallback) {
|
||||
int pn = snprintf(fallback, sizeof fallback, "%s/wwtest", self_dir);
|
||||
if (pn < 0 || (size_t)pn >= sizeof fallback) {
|
||||
fputs("ww test: package coordinator path is too long\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
char *fallback = NULL;
|
||||
const char *prog = override && override[0] ? override : NULL;
|
||||
if (prog == NULL) {
|
||||
fallback = sep_sprintf("%s/wwtest", self_dir);
|
||||
if (fallback == NULL) return 1;
|
||||
prog = fallback;
|
||||
}
|
||||
char **xargv = calloc((size_t)argc + 8, sizeof *xargv);
|
||||
if (argc < 0 || argc > INT_MAX - 10) {
|
||||
free(fallback);
|
||||
sep_fail_size();
|
||||
return 1;
|
||||
}
|
||||
char **xargv = calloc((size_t)argc + 10, sizeof *xargv);
|
||||
if (xargv == NULL) {
|
||||
fputs("ww test: cannot allocate package coordinator arguments\n",
|
||||
stderr);
|
||||
fprintf(stderr,
|
||||
"ww %s: cannot allocate package coordinator arguments\n",
|
||||
build_only ? "build" : "test");
|
||||
free(fallback);
|
||||
return 1;
|
||||
}
|
||||
int n = 0, dotted = 0;
|
||||
xargv[n++] = (char *)prog;
|
||||
xargv[n++] = "package";
|
||||
if (build_only) {
|
||||
xargv[n++] = "--ww-operation";
|
||||
xargv[n++] = "build";
|
||||
}
|
||||
xargv[n++] = "--ww-driver";
|
||||
xargv[n++] = (char *)self_path;
|
||||
if (root_identity != NULL) {
|
||||
@@ -154,8 +165,10 @@ exec_package_tests(int argc, char **argv, const char *target,
|
||||
if (add_dot && !dotted) xargv[n++] = ".";
|
||||
xargv[n] = NULL;
|
||||
execv(prog, xargv); /* inherit the caller's environment */
|
||||
fputs("ww test: cannot exec package test coordinator\n", stderr);
|
||||
fprintf(stderr, "ww %s: cannot exec package coordinator\n",
|
||||
build_only ? "build" : "test");
|
||||
free(xargv);
|
||||
free(fallback);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -558,6 +571,7 @@ enumerate_dir_ww(const char *dirpath, int variant, const char *test_package,
|
||||
const char *nm = ent->d_name;
|
||||
size_t nl = strlen(nm);
|
||||
if (nl <= 3) continue;
|
||||
if (nm[0] == '.' || nm[0] == '_') continue;
|
||||
if (strcmp(nm + nl - 3, ".ww") != 0) continue;
|
||||
int is_test = nl >= 8 && strcmp(nm + nl - 8, "_test.ww") == 0;
|
||||
if (variant == SEP_VARIANT_PRODUCTION && is_test) continue;
|
||||
@@ -573,7 +587,30 @@ enumerate_dir_ww(const char *dirpath, int variant, const char *test_package,
|
||||
return -2;
|
||||
}
|
||||
struct stat st;
|
||||
if (lstat(path, &st) != 0 || !S_ISREG(st.st_mode)) {
|
||||
if (lstat(path, &st) != 0) {
|
||||
fprintf(stderr,
|
||||
"ww: %s: package source is not a regular file\n", path);
|
||||
source_list_free(prod, nprod);
|
||||
source_list_free(tests, ntests);
|
||||
closedir(d);
|
||||
*out_files = NULL;
|
||||
return -2;
|
||||
}
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
if (stat(path, &st) != 0) {
|
||||
fprintf(stderr,
|
||||
"ww: %s: package source is not a regular file\n",
|
||||
path);
|
||||
source_list_free(prod, nprod);
|
||||
source_list_free(tests, ntests);
|
||||
closedir(d);
|
||||
*out_files = NULL;
|
||||
return -2;
|
||||
}
|
||||
/* go/build ignores a source-shaped symlink to a directory. */
|
||||
if (S_ISDIR(st.st_mode)) continue;
|
||||
}
|
||||
if (!S_ISREG(st.st_mode)) {
|
||||
fprintf(stderr,
|
||||
"ww: %s: package source is not a regular file\n", path);
|
||||
source_list_free(prod, nprod);
|
||||
@@ -3553,6 +3590,16 @@ validate_package_output_path(const char *out)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
validate_command_output_path(const char *out)
|
||||
{
|
||||
if (out == NULL || strlen(out) + 1 > (size_t)PATH_MAX) {
|
||||
fprintf(stderr, "ww: command output path is too long\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A coordinator-private completion marker distinguishes a newly linked
|
||||
* product from a caller-owned binary left behind by an earlier invocation. */
|
||||
static int
|
||||
@@ -3611,6 +3658,66 @@ invalidate_workdir_units(const char *scratch)
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct sep_created_dirs {
|
||||
char path[PATH_MAX];
|
||||
unsigned short offset[(PATH_MAX + 1) / 2];
|
||||
int n;
|
||||
};
|
||||
|
||||
static void
|
||||
sep_rollback_dirs(struct sep_created_dirs *created)
|
||||
{
|
||||
while (created->n > 0) {
|
||||
size_t at = created->offset[--created->n];
|
||||
char saved = created->path[at];
|
||||
created->path[at] = '\0';
|
||||
(void)rmdir(created->path);
|
||||
created->path[at] = saved;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create one caller-requested directory tree after semantic preflight. Record
|
||||
* exactly the prefixes minted by this call so a later pre-producer setup
|
||||
* failure can roll them back without touching pre-existing caller state. */
|
||||
static int
|
||||
sep_mkdirs(const char *path, mode_t mode, struct sep_created_dirs *created)
|
||||
{
|
||||
memset(created, 0, sizeof *created);
|
||||
size_t n = strlen(path);
|
||||
if (n == 0 || n >= PATH_MAX) return -1;
|
||||
char buf[PATH_MAX];
|
||||
memcpy(buf, path, n + 1);
|
||||
while (n > 1 && buf[n - 1] == '/') buf[--n] = '\0';
|
||||
memcpy(created->path, buf, n + 1);
|
||||
for (char *p = buf + (buf[0] == '/' ? 1 : 0); ; p++) {
|
||||
if (*p != '/' && *p != '\0') continue;
|
||||
char saved = *p;
|
||||
*p = '\0';
|
||||
if (buf[0] != '\0') {
|
||||
struct stat st;
|
||||
if (stat(buf, &st) != 0) {
|
||||
if (errno != ENOENT
|
||||
|| created->n >= (int)(sizeof created->offset
|
||||
/ sizeof created->offset[0])
|
||||
|| mkdir(buf, mode) != 0) {
|
||||
*p = saved;
|
||||
sep_rollback_dirs(created);
|
||||
return -1;
|
||||
}
|
||||
created->offset[created->n++] =
|
||||
(unsigned short)(p - buf);
|
||||
} else if (!S_ISDIR(st.st_mode)) {
|
||||
*p = saved;
|
||||
sep_rollback_dirs(created);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
*p = saved;
|
||||
if (saved == '\0') break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* build_sep_plan — discover dependencies for every requested product in one
|
||||
* package universe, compile the dependency-first union once, then link each
|
||||
* root from its own complete reachable archive closure. The dependency-first
|
||||
@@ -3625,7 +3732,8 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
const struct seplinkflags *linkflags, int publish_package,
|
||||
int require_command, int is_test,
|
||||
struct sepproduct *products, int nproducts, int emit_asm,
|
||||
const char *workdir, char *scratchout, size_t scratchoutsz,
|
||||
const char *workdir, int create_workdir, const char *create_output_dir,
|
||||
char *scratchout, size_t scratchoutsz,
|
||||
struct sepgraph **graphout)
|
||||
{
|
||||
sep_fatal_allocation = 0;
|
||||
@@ -3679,10 +3787,14 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
if (stem == NULL) return 1;
|
||||
const char *ostem = (objstem && objstem[0]) ? objstem : stem;
|
||||
int warm = workdir != NULL && workdir[0] != 0;
|
||||
int workdir_exists = 0;
|
||||
char scratch[PATH_MAX];
|
||||
if (warm) {
|
||||
struct stat wst;
|
||||
if (stat(workdir, &wst) != 0 || !S_ISDIR(wst.st_mode)) {
|
||||
int wr = stat(workdir, &wst);
|
||||
if (wr == 0 && S_ISDIR(wst.st_mode)) {
|
||||
workdir_exists = 1;
|
||||
} else if (wr == 0 || !create_workdir || errno != ENOENT) {
|
||||
fprintf(stderr, "ww: workdir %s is not a directory\n",
|
||||
workdir);
|
||||
return 1;
|
||||
@@ -3690,7 +3802,10 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
/* The workdir is caller-owned and persistent: no acquisition,
|
||||
* no refusal, and scratchout stays empty so the wrapper never
|
||||
* cleans it. */
|
||||
if (strlen(workdir) + 1 > sizeof scratch) return 1;
|
||||
if (strlen(workdir) + 1 > sizeof scratch) {
|
||||
fprintf(stderr, "ww: workdir path is too long\n");
|
||||
return 1;
|
||||
}
|
||||
memcpy(scratch, workdir, strlen(workdir) + 1);
|
||||
} else {
|
||||
int n = snprintf(scratch, sizeof scratch, "%s.sepwork", ostem);
|
||||
@@ -3930,12 +4045,18 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
products[i].root = mainpkg;
|
||||
}
|
||||
}
|
||||
int root_package = !is_test
|
||||
for (int i = 0; i < nproducts; i++) {
|
||||
int root = products[i].root;
|
||||
if (!g->pkg[root].failed && sep_root_is_command(&g->pkg[root])
|
||||
&& validate_command_output_path(products[i].out) < 0)
|
||||
return 1;
|
||||
}
|
||||
int root_package = !is_test && nproducts == 1
|
||||
&& !g->pkg[products[0].root].failed
|
||||
&& !sep_root_is_command(&g->pkg[products[0].root]);
|
||||
if (sep_validate_artifact_paths(g, scratch) < 0)
|
||||
return 1;
|
||||
if (warm && sep_validate_workdir_owners(g, scratch) < 0)
|
||||
if (warm && workdir_exists && sep_validate_workdir_owners(g, scratch) < 0)
|
||||
return 1;
|
||||
int *order = calloc((size_t)g->n, sizeof *order);
|
||||
int *stack = calloc((size_t)g->n, sizeof *stack);
|
||||
@@ -4004,9 +4125,30 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
/* Product completion and persistent package state remain untouched until
|
||||
* all source-derived imports, contextual legality, cycles, command kind,
|
||||
* output paths, and action closures have passed their pre-tool checks. */
|
||||
struct sep_created_dirs created_output = {0};
|
||||
struct sep_created_dirs created_work = {0};
|
||||
if (create_output_dir != NULL && create_output_dir[0] != '\0'
|
||||
&& sep_mkdirs(create_output_dir, 0700, &created_output) != 0) {
|
||||
fprintf(stderr, "ww: cannot create build output directory %s\n",
|
||||
create_output_dir);
|
||||
free(order);
|
||||
return 1;
|
||||
}
|
||||
if (warm && !workdir_exists) {
|
||||
if (!create_workdir
|
||||
|| sep_mkdirs(scratch, 0700, &created_work) != 0) {
|
||||
fprintf(stderr, "ww: workdir %s is not a directory\n", scratch);
|
||||
sep_rollback_dirs(&created_output);
|
||||
free(order);
|
||||
return 1;
|
||||
}
|
||||
workdir_exists = 1;
|
||||
}
|
||||
if (!warm) {
|
||||
if (mkdir(scratch, 0755) != 0) {
|
||||
fprintf(stderr, "ww: cannot create scratch %s\n", scratch);
|
||||
sep_rollback_dirs(&created_work);
|
||||
sep_rollback_dirs(&created_output);
|
||||
free(order);
|
||||
return 1;
|
||||
}
|
||||
@@ -4251,7 +4393,19 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (emit_asm) { free(order); return any_failed ? 1 : 0; }
|
||||
if (emit_asm) {
|
||||
for (int i = 0; i < nproducts; i++) {
|
||||
int root = products[i].root;
|
||||
if (g->pkg[root].failed) { any_failed = 1; continue; }
|
||||
if (record_product_status(products[i].status) != 0) {
|
||||
fprintf(stderr, "ww: cannot record package-build product\n");
|
||||
g->pkg[root].failed = 1;
|
||||
any_failed = 1;
|
||||
}
|
||||
}
|
||||
free(order);
|
||||
return any_failed ? 1 : 0;
|
||||
}
|
||||
if (root_package) {
|
||||
int root = products[0].root;
|
||||
if (g->pkg[root].failed) { free(order); return 1; }
|
||||
@@ -4274,6 +4428,11 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (record_product_status(products[0].status) != 0) {
|
||||
fprintf(stderr, "ww: cannot record package-build product\n");
|
||||
free(order);
|
||||
return 1;
|
||||
}
|
||||
free(order);
|
||||
return 0;
|
||||
}
|
||||
@@ -4303,6 +4462,15 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
int root = products[i].root;
|
||||
int variant_root = products[i].variant_root;
|
||||
if (g->pkg[root].failed) { any_failed = 1; continue; }
|
||||
if (!is_test && !sep_root_is_command(&g->pkg[root])) {
|
||||
if (record_product_status(products[i].status) != 0) {
|
||||
fprintf(stderr,
|
||||
"ww: cannot record package-build product\n");
|
||||
g->pkg[root].failed = 1;
|
||||
any_failed = 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
for (int pi = 0; pi < g->n; pi++) g->pkg[pi].color = 0;
|
||||
int *linkorder = calloc((size_t)g->n, sizeof *linkorder);
|
||||
int *linkstack = calloc((size_t)g->n, sizeof *linkstack);
|
||||
@@ -4422,7 +4590,7 @@ build_one_sep(const char *src, int entry_is_dir, const char *root_identity,
|
||||
product.artifact = "__root";
|
||||
int r = build_one_sep_impl(src, entry_is_dir, out, objstem,
|
||||
extra_includes, linkflags, publish_package, require_command, is_test,
|
||||
&product, 1, emit_asm, workdir, scratch,
|
||||
&product, 1, emit_asm, workdir, 0, NULL, scratch,
|
||||
sizeof scratch, &g);
|
||||
sep_graph_free(g);
|
||||
if (!keepscratch && scratch[0]) {
|
||||
@@ -4456,15 +4624,18 @@ build_one_sep(const char *src, int entry_is_dir, const char *root_identity,
|
||||
static int
|
||||
build_package_tests(const char *src, const char *root_identity,
|
||||
const char *extra_includes, const char *workdir,
|
||||
struct sepproduct *products, int nproducts)
|
||||
struct sepproduct *products, int nproducts, int is_test,
|
||||
int publish_package, const struct seplinkflags *linkflags, int emit_asm,
|
||||
int create_workdir, const char *create_output_dir)
|
||||
{
|
||||
char scratch[PATH_MAX] = {0};
|
||||
struct sepgraph *g = NULL;
|
||||
for (int i = 0; i < nproducts; i++)
|
||||
products[i].identity = root_identity;
|
||||
int r = build_one_sep_impl(src, 1, products[0].out,
|
||||
products[0].out, extra_includes, NULL, 0, 0, 1,
|
||||
products, nproducts, 0, workdir, scratch, sizeof scratch, &g);
|
||||
products[0].out, extra_includes, linkflags, publish_package, 0, is_test,
|
||||
products, nproducts, emit_asm, workdir, create_workdir,
|
||||
create_output_dir, scratch, sizeof scratch, &g);
|
||||
sep_graph_free(g);
|
||||
return r;
|
||||
}
|
||||
@@ -4607,13 +4778,18 @@ parse_build_flags(const char *cmd, int argc, char **argv,
|
||||
struct seplinkflags *linkflags,
|
||||
char *outpath, size_t outsz,
|
||||
char *workdir, size_t workdirsz,
|
||||
const char **src_out, int *emit_asm_out)
|
||||
const char **src_out, int *emit_asm_out, int *terminator_out)
|
||||
{
|
||||
*src_out = NULL;
|
||||
if (emit_asm_out) *emit_asm_out = 0;
|
||||
if (terminator_out) *terminator_out = 0;
|
||||
int i = 0;
|
||||
for (; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-S") == 0) {
|
||||
if (strcmp(cmd, "build") == 0 && strcmp(argv[i], "--") == 0) {
|
||||
if (terminator_out) *terminator_out = 1;
|
||||
i++;
|
||||
break;
|
||||
} else if (strcmp(argv[i], "-S") == 0) {
|
||||
if (emit_asm_out == NULL) {
|
||||
fprintf(stderr, "ww %s: unknown flag\n", cmd);
|
||||
return -1;
|
||||
@@ -4699,6 +4875,12 @@ parse_build_flags(const char *cmd, int argc, char **argv,
|
||||
return -1;
|
||||
} else if (*src_out == NULL) {
|
||||
*src_out = argv[i];
|
||||
/* Go's FlagSet stops at the first positional. For build,
|
||||
* everything after it is package-request input, even "--". */
|
||||
if (strcmp(cmd, "build") == 0) {
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break; /* leave remaining argv to caller (run-args) */
|
||||
}
|
||||
@@ -4717,14 +4899,20 @@ do_build(int argc, char **argv)
|
||||
char outflag[PATH_MAX] = {0};
|
||||
char workdir[PATH_MAX] = {0};
|
||||
int emit_asm = 0;
|
||||
if (parse_build_flags("build", argc, argv, incs, incsz,
|
||||
int saw_terminator = 0;
|
||||
int next = parse_build_flags("build", argc, argv, incs, incsz,
|
||||
&linkflags,
|
||||
outflag, sizeof outflag, workdir, sizeof workdir,
|
||||
&src, &emit_asm) < 0) {
|
||||
&src, &emit_asm, &saw_terminator);
|
||||
if (next < 0) {
|
||||
free(incs);
|
||||
return 2;
|
||||
}
|
||||
if (src == NULL) src = ".";
|
||||
if (strstr(src, "...") != NULL || next < argc || saw_terminator) {
|
||||
free(incs);
|
||||
return exec_package_command(argc, argv, src, NULL, NULL, 0, 1);
|
||||
}
|
||||
struct stat requested;
|
||||
int literal = stat(src, &requested) == 0;
|
||||
char resolved[PATH_MAX];
|
||||
@@ -4770,7 +4958,7 @@ do_run(int argc, char **argv)
|
||||
char outflag[PATH_MAX] = {0}; /* -o accepted+ignored: run always uses the temp */
|
||||
int next = parse_build_flags("run", argc, argv, incs, incsz,
|
||||
&linkflags,
|
||||
outflag, sizeof outflag, NULL, 0, &src, NULL);
|
||||
outflag, sizeof outflag, NULL, 0, &src, NULL, NULL);
|
||||
if (next < 0) { free(incs); return 2; }
|
||||
if (src == NULL) src = ".";
|
||||
struct stat requested;
|
||||
@@ -4865,6 +5053,11 @@ do_test(int argc, char **argv)
|
||||
char outstem[PATH_MAX] = {0};
|
||||
char workdir[PATH_MAX] = {0};
|
||||
int packageopts = 0;
|
||||
int package_build = 0;
|
||||
int package_publish = 0;
|
||||
int package_create_workdir = 0;
|
||||
const char *package_create_output_dir = NULL;
|
||||
struct seplinkflags package_linkflags = {0};
|
||||
int afterdash = 0;
|
||||
const char *request_identity = NULL;
|
||||
/* #17: an optional second positional after the target is a fnmatch
|
||||
@@ -4904,6 +5097,36 @@ do_test(int argc, char **argv)
|
||||
return 2;
|
||||
}
|
||||
request_identity = argv[++i];
|
||||
} else if (strcmp(argv[i], "--ww-package-build") == 0) {
|
||||
if (package_build) {
|
||||
fprintf(stderr,
|
||||
"ww test: invalid --ww-package-build\n");
|
||||
return 2;
|
||||
}
|
||||
package_build = 1;
|
||||
compileonly = 1;
|
||||
} else if (strcmp(argv[i], "--ww-package-publish") == 0) {
|
||||
if (package_publish) {
|
||||
fprintf(stderr,
|
||||
"ww test: invalid --ww-package-publish\n");
|
||||
return 2;
|
||||
}
|
||||
package_publish = 1;
|
||||
} else if (strcmp(argv[i], "--ww-create-workdir") == 0) {
|
||||
if (package_create_workdir) {
|
||||
fprintf(stderr,
|
||||
"ww test: invalid --ww-create-workdir\n");
|
||||
return 2;
|
||||
}
|
||||
package_create_workdir = 1;
|
||||
} else if (strcmp(argv[i], "--ww-create-output-dir") == 0) {
|
||||
if (i + 1 >= argc || package_create_output_dir != NULL
|
||||
|| argv[i + 1][0] == '\0') {
|
||||
fprintf(stderr,
|
||||
"ww test: invalid --ww-create-output-dir\n");
|
||||
return 2;
|
||||
}
|
||||
package_create_output_dir = argv[++i];
|
||||
} else if (strcmp(argv[i], "--ww-package-test") == 0) {
|
||||
if (i + 5 >= argc) {
|
||||
fprintf(stderr,
|
||||
@@ -4954,6 +5177,40 @@ do_test(int argc, char **argv)
|
||||
nproducts++;
|
||||
} else if (strcmp(argv[i], "-S") == 0) {
|
||||
emit_asm = 1;
|
||||
} else if (package_build
|
||||
&& strncmp(argv[i], "-l", 2) == 0 && argv[i][2]) {
|
||||
if (package_linkflags.nlibs >= SEP_MAXLFLAGS) {
|
||||
fprintf(stderr, "ww test: too many -l\n");
|
||||
return 2;
|
||||
}
|
||||
package_linkflags.libs[package_linkflags.nlibs++] = argv[i] + 2;
|
||||
} else if (package_build && strcmp(argv[i], "-l") == 0) {
|
||||
if (i + 1 >= argc) {
|
||||
fprintf(stderr, "ww test: -l needs an argument\n");
|
||||
return 2;
|
||||
}
|
||||
if (package_linkflags.nlibs >= SEP_MAXLFLAGS) {
|
||||
fprintf(stderr, "ww test: too many -l\n");
|
||||
return 2;
|
||||
}
|
||||
package_linkflags.libs[package_linkflags.nlibs++] = argv[++i];
|
||||
} else if (package_build && strcmp(argv[i], "-L") == 0) {
|
||||
if (i + 1 >= argc) {
|
||||
fprintf(stderr, "ww test: -L needs an argument\n");
|
||||
return 2;
|
||||
}
|
||||
if (package_linkflags.nlibdirs >= SEP_MAXLFLAGS) {
|
||||
fprintf(stderr, "ww test: too many -L\n");
|
||||
return 2;
|
||||
}
|
||||
package_linkflags.libdirs[package_linkflags.nlibdirs++] = argv[++i];
|
||||
} else if (package_build
|
||||
&& strncmp(argv[i], "-L", 2) == 0 && argv[i][2]) {
|
||||
if (package_linkflags.nlibdirs >= SEP_MAXLFLAGS) {
|
||||
fprintf(stderr, "ww test: too many -L\n");
|
||||
return 2;
|
||||
}
|
||||
package_linkflags.libdirs[package_linkflags.nlibdirs++] = argv[i] + 2;
|
||||
} else if (strcmp(argv[i], "-list") == 0) {
|
||||
packageopts = 1;
|
||||
} else if (strcmp(argv[i], "-j") == 0 ||
|
||||
@@ -5002,7 +5259,7 @@ do_test(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
const char *target = src ? src : ".";
|
||||
if (emit_asm && !outstem[0]) {
|
||||
if (emit_asm && !outstem[0] && nproducts == 0) {
|
||||
fprintf(stderr, "ww test: -S needs -o\n");
|
||||
return 2;
|
||||
}
|
||||
@@ -5033,17 +5290,66 @@ do_test(int argc, char **argv)
|
||||
"ww test: package-test variant rejects package options\n");
|
||||
return 2;
|
||||
}
|
||||
if (package_build && nproducts == 0) {
|
||||
fprintf(stderr, "ww test: --ww-package-build needs products\n");
|
||||
return 2;
|
||||
}
|
||||
if (package_publish && (!package_build || nproducts != 1)) {
|
||||
fprintf(stderr, "ww test: invalid --ww-package-publish\n");
|
||||
return 2;
|
||||
}
|
||||
if (package_create_output_dir != NULL && !package_build) {
|
||||
fprintf(stderr, "ww test: invalid private directory creation\n");
|
||||
return 2;
|
||||
}
|
||||
if (package_create_workdir && nproducts == 0) {
|
||||
fprintf(stderr, "ww test: invalid private directory creation\n");
|
||||
return 2;
|
||||
}
|
||||
if (package_create_workdir && !workdir[0]) {
|
||||
fprintf(stderr, "ww test: --ww-create-workdir needs -w\n");
|
||||
return 2;
|
||||
}
|
||||
if (!package_build && (package_linkflags.nlibdirs != 0
|
||||
|| package_linkflags.nlibs != 0)) {
|
||||
fprintf(stderr, "ww test: unknown flag\n");
|
||||
return 2;
|
||||
}
|
||||
if (package_build) {
|
||||
for (int i = 0; i < nproducts; i++) {
|
||||
if (products[i].variant != SEP_VARIANT_PRODUCTION) {
|
||||
fprintf(stderr,
|
||||
"ww test: package-build products must be production\n");
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pattern != NULL) {
|
||||
struct stat first;
|
||||
if (stat(target, &first) != 0 || !S_ISREG(first.st_mode)) {
|
||||
char first_resolved[PATH_MAX];
|
||||
int first_is_dir = 0;
|
||||
if (stat(target, &first) == 0
|
||||
|| !resolve_module(target, incs, first_resolved,
|
||||
sizeof first_resolved, &first_is_dir)
|
||||
|| first_is_dir) {
|
||||
return exec_package_command(argc, argv, src,
|
||||
first_is_dir ? first_resolved : NULL,
|
||||
first_is_dir ? target : request_identity,
|
||||
0, 0);
|
||||
}
|
||||
/* A logical import that resolves to one regular source keeps
|
||||
* the historical second-positional test-name filter. */
|
||||
}
|
||||
}
|
||||
if (nproducts != 0 && outstem[0]) {
|
||||
fprintf(stderr,
|
||||
"ww test: package-test products reject -o\n");
|
||||
return 2;
|
||||
}
|
||||
/* Go's ./... form: a trailing "..." element is a package-tree
|
||||
* request for the coordinator, never a literal path — recognized
|
||||
* before stat, with the directory-mode rejects. */
|
||||
size_t tlen = strlen(target);
|
||||
if (strcmp(target, "...") == 0 ||
|
||||
(tlen >= 4 && strcmp(target + tlen - 4, "/...") == 0)) {
|
||||
/* Every local spelling containing "..." is a package pattern. It enters
|
||||
* request selection before literal-path or logical-import resolution. */
|
||||
if (strstr(target, "...") != NULL) {
|
||||
if (nproducts != 0) {
|
||||
fprintf(stderr,
|
||||
"ww test: package-test variant needs one directory\n");
|
||||
@@ -5061,14 +5367,9 @@ do_test(int argc, char **argv)
|
||||
"ww test: -o needs -c for a package target\n");
|
||||
return 2;
|
||||
}
|
||||
if (pattern) {
|
||||
fprintf(stderr,
|
||||
"ww test: pattern needs a single test file\n");
|
||||
return 2;
|
||||
}
|
||||
/* -w forwards: the coordinator keys one persistent driver
|
||||
* workdir for the complete selected test request. */
|
||||
return exec_package_tests(argc, argv, src, NULL, NULL, 0);
|
||||
/* -w forwards one caller-owned semantic-action store shared by
|
||||
* the complete selected package universe. */
|
||||
return exec_package_command(argc, argv, src, NULL, NULL, 0, 0);
|
||||
}
|
||||
struct stat st;
|
||||
if (stat(target, &st) != 0) {
|
||||
@@ -5082,7 +5383,7 @@ do_test(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
if (is_dir) {
|
||||
if (emit_asm) {
|
||||
if (emit_asm && nproducts == 0) {
|
||||
fprintf(stderr,
|
||||
"ww test: -S needs a single test file\n");
|
||||
return 2;
|
||||
@@ -5092,11 +5393,6 @@ do_test(int argc, char **argv)
|
||||
"ww test: -o needs -c for a package target\n");
|
||||
return 2;
|
||||
}
|
||||
if (pattern) {
|
||||
fprintf(stderr,
|
||||
"ww test: pattern needs a single test file\n");
|
||||
return 2;
|
||||
}
|
||||
if (nproducts != 0) {
|
||||
if (!compileonly) {
|
||||
fprintf(stderr,
|
||||
@@ -5104,13 +5400,16 @@ do_test(int argc, char **argv)
|
||||
return 2;
|
||||
}
|
||||
int r = build_package_tests(resolved, request_identity,
|
||||
incs, workdir, products, nproducts);
|
||||
incs, workdir, products, nproducts,
|
||||
package_build ? 0 : 1, package_publish,
|
||||
package_build ? &package_linkflags : NULL, emit_asm,
|
||||
package_create_workdir, package_create_output_dir);
|
||||
free(products);
|
||||
free(incs);
|
||||
return r;
|
||||
}
|
||||
return exec_package_tests(argc, argv, src, resolved,
|
||||
request_identity != NULL ? request_identity : target, 0);
|
||||
return exec_package_command(argc, argv, src, resolved,
|
||||
request_identity != NULL ? request_identity : target, 0, 0);
|
||||
}
|
||||
if (packageopts) {
|
||||
fprintf(stderr,
|
||||
@@ -5253,7 +5552,7 @@ do_test(int argc, char **argv)
|
||||
fprintf(stderr, "ww test: %s is neither file nor directory\n", target);
|
||||
return 1;
|
||||
}
|
||||
if (emit_asm) {
|
||||
if (emit_asm && nproducts == 0) {
|
||||
fprintf(stderr, "ww test: -S needs a single test file\n");
|
||||
return 2;
|
||||
}
|
||||
@@ -5261,12 +5560,6 @@ do_test(int argc, char **argv)
|
||||
fprintf(stderr, "ww test: -o needs -c for a package target\n");
|
||||
return 2;
|
||||
}
|
||||
/* The second bare positional remains the legacy single-file filter form;
|
||||
* package filtering uses explicit -run/-filter options. */
|
||||
if (pattern) {
|
||||
fprintf(stderr, "ww test: pattern needs a single test file\n");
|
||||
return 2;
|
||||
}
|
||||
if (nproducts != 0) {
|
||||
if (!compileonly) {
|
||||
fprintf(stderr,
|
||||
@@ -5274,13 +5567,15 @@ do_test(int argc, char **argv)
|
||||
return 2;
|
||||
}
|
||||
int r = build_package_tests(target, request_identity, incs, workdir,
|
||||
products, nproducts);
|
||||
products, nproducts, package_build ? 0 : 1,
|
||||
package_publish, package_build ? &package_linkflags : NULL,
|
||||
emit_asm, package_create_workdir, package_create_output_dir);
|
||||
free(products);
|
||||
free(incs);
|
||||
return r;
|
||||
}
|
||||
return exec_package_tests(argc, argv, src, NULL, request_identity,
|
||||
src == NULL);
|
||||
return exec_package_command(argc, argv, src, NULL, request_identity,
|
||||
src == NULL, 0);
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
227
internal/wwpackage/isprint.ww
Normal file
227
internal/wwpackage/isprint.ww
Normal file
@@ -0,0 +1,227 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license.
|
||||
//
|
||||
// Go 1.26.5 strconv.IsPrint tables, generated in the pinned Go tree at
|
||||
// c19862e5f8415b4f24b189d065ed739517c548ba. They keep unmatched-pattern
|
||||
// diagnostics byte-for-byte aligned with strconv.Quote without importing a
|
||||
// Unicode database or adding runtime lookup state.
|
||||
|
||||
package wwpackage;
|
||||
|
||||
let pkgprint16: [424]u16 = [
|
||||
0x0020u16, 0x007eu16, 0x00a1u16, 0x0377u16, 0x037au16, 0x037fu16, 0x0384u16, 0x0556u16,
|
||||
0x0559u16, 0x058au16, 0x058du16, 0x05c7u16, 0x05d0u16, 0x05eau16, 0x05efu16, 0x05f4u16,
|
||||
0x0606u16, 0x070du16, 0x0710u16, 0x074au16, 0x074du16, 0x07b1u16, 0x07c0u16, 0x07fau16,
|
||||
0x07fdu16, 0x082du16, 0x0830u16, 0x085bu16, 0x085eu16, 0x086au16, 0x0870u16, 0x088eu16,
|
||||
0x0898u16, 0x098cu16, 0x098fu16, 0x0990u16, 0x0993u16, 0x09b2u16, 0x09b6u16, 0x09b9u16,
|
||||
0x09bcu16, 0x09c4u16, 0x09c7u16, 0x09c8u16, 0x09cbu16, 0x09ceu16, 0x09d7u16, 0x09d7u16,
|
||||
0x09dcu16, 0x09e3u16, 0x09e6u16, 0x09feu16, 0x0a01u16, 0x0a0au16, 0x0a0fu16, 0x0a10u16,
|
||||
0x0a13u16, 0x0a39u16, 0x0a3cu16, 0x0a42u16, 0x0a47u16, 0x0a48u16, 0x0a4bu16, 0x0a4du16,
|
||||
0x0a51u16, 0x0a51u16, 0x0a59u16, 0x0a5eu16, 0x0a66u16, 0x0a76u16, 0x0a81u16, 0x0ab9u16,
|
||||
0x0abcu16, 0x0acdu16, 0x0ad0u16, 0x0ad0u16, 0x0ae0u16, 0x0ae3u16, 0x0ae6u16, 0x0af1u16,
|
||||
0x0af9u16, 0x0b0cu16, 0x0b0fu16, 0x0b10u16, 0x0b13u16, 0x0b39u16, 0x0b3cu16, 0x0b44u16,
|
||||
0x0b47u16, 0x0b48u16, 0x0b4bu16, 0x0b4du16, 0x0b55u16, 0x0b57u16, 0x0b5cu16, 0x0b63u16,
|
||||
0x0b66u16, 0x0b77u16, 0x0b82u16, 0x0b8au16, 0x0b8eu16, 0x0b95u16, 0x0b99u16, 0x0b9fu16,
|
||||
0x0ba3u16, 0x0ba4u16, 0x0ba8u16, 0x0baau16, 0x0baeu16, 0x0bb9u16, 0x0bbeu16, 0x0bc2u16,
|
||||
0x0bc6u16, 0x0bcdu16, 0x0bd0u16, 0x0bd0u16, 0x0bd7u16, 0x0bd7u16, 0x0be6u16, 0x0bfau16,
|
||||
0x0c00u16, 0x0c39u16, 0x0c3cu16, 0x0c4du16, 0x0c55u16, 0x0c5au16, 0x0c5du16, 0x0c5du16,
|
||||
0x0c60u16, 0x0c63u16, 0x0c66u16, 0x0c6fu16, 0x0c77u16, 0x0cb9u16, 0x0cbcu16, 0x0ccdu16,
|
||||
0x0cd5u16, 0x0cd6u16, 0x0cddu16, 0x0ce3u16, 0x0ce6u16, 0x0cf3u16, 0x0d00u16, 0x0d4fu16,
|
||||
0x0d54u16, 0x0d63u16, 0x0d66u16, 0x0d96u16, 0x0d9au16, 0x0dbdu16, 0x0dc0u16, 0x0dc6u16,
|
||||
0x0dcau16, 0x0dcau16, 0x0dcfu16, 0x0ddfu16, 0x0de6u16, 0x0defu16, 0x0df2u16, 0x0df4u16,
|
||||
0x0e01u16, 0x0e3au16, 0x0e3fu16, 0x0e5bu16, 0x0e81u16, 0x0ebdu16, 0x0ec0u16, 0x0ed9u16,
|
||||
0x0edcu16, 0x0edfu16, 0x0f00u16, 0x0f6cu16, 0x0f71u16, 0x0fdau16, 0x1000u16, 0x10c7u16,
|
||||
0x10cdu16, 0x10cdu16, 0x10d0u16, 0x124du16, 0x1250u16, 0x125du16, 0x1260u16, 0x128du16,
|
||||
0x1290u16, 0x12b5u16, 0x12b8u16, 0x12c5u16, 0x12c8u16, 0x1315u16, 0x1318u16, 0x135au16,
|
||||
0x135du16, 0x137cu16, 0x1380u16, 0x1399u16, 0x13a0u16, 0x13f5u16, 0x13f8u16, 0x13fdu16,
|
||||
0x1400u16, 0x169cu16, 0x16a0u16, 0x16f8u16, 0x1700u16, 0x1715u16, 0x171fu16, 0x1736u16,
|
||||
0x1740u16, 0x1753u16, 0x1760u16, 0x1773u16, 0x1780u16, 0x17ddu16, 0x17e0u16, 0x17e9u16,
|
||||
0x17f0u16, 0x17f9u16, 0x1800u16, 0x1819u16, 0x1820u16, 0x1878u16, 0x1880u16, 0x18aau16,
|
||||
0x18b0u16, 0x18f5u16, 0x1900u16, 0x192bu16, 0x1930u16, 0x193bu16, 0x1940u16, 0x1940u16,
|
||||
0x1944u16, 0x196du16, 0x1970u16, 0x1974u16, 0x1980u16, 0x19abu16, 0x19b0u16, 0x19c9u16,
|
||||
0x19d0u16, 0x19dau16, 0x19deu16, 0x1a1bu16, 0x1a1eu16, 0x1a7cu16, 0x1a7fu16, 0x1a89u16,
|
||||
0x1a90u16, 0x1a99u16, 0x1aa0u16, 0x1aadu16, 0x1ab0u16, 0x1aceu16, 0x1b00u16, 0x1b4cu16,
|
||||
0x1b50u16, 0x1bf3u16, 0x1bfcu16, 0x1c37u16, 0x1c3bu16, 0x1c49u16, 0x1c4du16, 0x1c88u16,
|
||||
0x1c90u16, 0x1cbau16, 0x1cbdu16, 0x1cc7u16, 0x1cd0u16, 0x1cfau16, 0x1d00u16, 0x1f15u16,
|
||||
0x1f18u16, 0x1f1du16, 0x1f20u16, 0x1f45u16, 0x1f48u16, 0x1f4du16, 0x1f50u16, 0x1f7du16,
|
||||
0x1f80u16, 0x1fd3u16, 0x1fd6u16, 0x1fefu16, 0x1ff2u16, 0x1ffeu16, 0x2010u16, 0x2027u16,
|
||||
0x2030u16, 0x205eu16, 0x2070u16, 0x2071u16, 0x2074u16, 0x209cu16, 0x20a0u16, 0x20c0u16,
|
||||
0x20d0u16, 0x20f0u16, 0x2100u16, 0x218bu16, 0x2190u16, 0x2426u16, 0x2440u16, 0x244au16,
|
||||
0x2460u16, 0x2b73u16, 0x2b76u16, 0x2cf3u16, 0x2cf9u16, 0x2d27u16, 0x2d2du16, 0x2d2du16,
|
||||
0x2d30u16, 0x2d67u16, 0x2d6fu16, 0x2d70u16, 0x2d7fu16, 0x2d96u16, 0x2da0u16, 0x2e5du16,
|
||||
0x2e80u16, 0x2ef3u16, 0x2f00u16, 0x2fd5u16, 0x2ff0u16, 0x2ffbu16, 0x3001u16, 0x3096u16,
|
||||
0x3099u16, 0x30ffu16, 0x3105u16, 0x31e3u16, 0x31f0u16, 0xa48cu16, 0xa490u16, 0xa4c6u16,
|
||||
0xa4d0u16, 0xa62bu16, 0xa640u16, 0xa6f7u16, 0xa700u16, 0xa7cau16, 0xa7d0u16, 0xa7d9u16,
|
||||
0xa7f2u16, 0xa82cu16, 0xa830u16, 0xa839u16, 0xa840u16, 0xa877u16, 0xa880u16, 0xa8c5u16,
|
||||
0xa8ceu16, 0xa8d9u16, 0xa8e0u16, 0xa953u16, 0xa95fu16, 0xa97cu16, 0xa980u16, 0xa9d9u16,
|
||||
0xa9deu16, 0xaa36u16, 0xaa40u16, 0xaa4du16, 0xaa50u16, 0xaa59u16, 0xaa5cu16, 0xaac2u16,
|
||||
0xaadbu16, 0xaaf6u16, 0xab01u16, 0xab06u16, 0xab09u16, 0xab0eu16, 0xab11u16, 0xab16u16,
|
||||
0xab20u16, 0xab6bu16, 0xab70u16, 0xabedu16, 0xabf0u16, 0xabf9u16, 0xac00u16, 0xd7a3u16,
|
||||
0xd7b0u16, 0xd7c6u16, 0xd7cbu16, 0xd7fbu16, 0xf900u16, 0xfa6du16, 0xfa70u16, 0xfad9u16,
|
||||
0xfb00u16, 0xfb06u16, 0xfb13u16, 0xfb17u16, 0xfb1du16, 0xfbc2u16, 0xfbd3u16, 0xfd8fu16,
|
||||
0xfd92u16, 0xfdc7u16, 0xfdcfu16, 0xfdcfu16, 0xfdf0u16, 0xfe19u16, 0xfe20u16, 0xfe6bu16,
|
||||
0xfe70u16, 0xfefcu16, 0xff01u16, 0xffbeu16, 0xffc2u16, 0xffc7u16, 0xffcau16, 0xffcfu16,
|
||||
0xffd2u16, 0xffd7u16, 0xffdau16, 0xffdcu16, 0xffe0u16, 0xffeeu16, 0xfffcu16, 0xfffdu16,
|
||||
];
|
||||
|
||||
let pkgnotprint16: [133]u16 = [
|
||||
0x00adu16, 0x038bu16, 0x038du16, 0x03a2u16, 0x0530u16, 0x0590u16, 0x061cu16, 0x06ddu16,
|
||||
0x083fu16, 0x085fu16, 0x08e2u16, 0x0984u16, 0x09a9u16, 0x09b1u16, 0x09deu16, 0x0a04u16,
|
||||
0x0a29u16, 0x0a31u16, 0x0a34u16, 0x0a37u16, 0x0a3du16, 0x0a5du16, 0x0a84u16, 0x0a8eu16,
|
||||
0x0a92u16, 0x0aa9u16, 0x0ab1u16, 0x0ab4u16, 0x0ac6u16, 0x0acau16, 0x0b00u16, 0x0b04u16,
|
||||
0x0b29u16, 0x0b31u16, 0x0b34u16, 0x0b5eu16, 0x0b84u16, 0x0b91u16, 0x0b9bu16, 0x0b9du16,
|
||||
0x0bc9u16, 0x0c0du16, 0x0c11u16, 0x0c29u16, 0x0c45u16, 0x0c49u16, 0x0c57u16, 0x0c8du16,
|
||||
0x0c91u16, 0x0ca9u16, 0x0cb4u16, 0x0cc5u16, 0x0cc9u16, 0x0cdfu16, 0x0cf0u16, 0x0d0du16,
|
||||
0x0d11u16, 0x0d45u16, 0x0d49u16, 0x0d80u16, 0x0d84u16, 0x0db2u16, 0x0dbcu16, 0x0dd5u16,
|
||||
0x0dd7u16, 0x0e83u16, 0x0e85u16, 0x0e8bu16, 0x0ea4u16, 0x0ea6u16, 0x0ec5u16, 0x0ec7u16,
|
||||
0x0ecfu16, 0x0f48u16, 0x0f98u16, 0x0fbdu16, 0x0fcdu16, 0x10c6u16, 0x1249u16, 0x1257u16,
|
||||
0x1259u16, 0x1289u16, 0x12b1u16, 0x12bfu16, 0x12c1u16, 0x12d7u16, 0x1311u16, 0x1680u16,
|
||||
0x176du16, 0x1771u16, 0x180eu16, 0x191fu16, 0x1a5fu16, 0x1b7fu16, 0x1f58u16, 0x1f5au16,
|
||||
0x1f5cu16, 0x1f5eu16, 0x1fb5u16, 0x1fc5u16, 0x1fdcu16, 0x1ff5u16, 0x208fu16, 0x2b96u16,
|
||||
0x2d26u16, 0x2da7u16, 0x2dafu16, 0x2db7u16, 0x2dbfu16, 0x2dc7u16, 0x2dcfu16, 0x2dd7u16,
|
||||
0x2ddfu16, 0x2e9au16, 0x3040u16, 0x3130u16, 0x318fu16, 0x321fu16, 0xa7d2u16, 0xa7d4u16,
|
||||
0xa9ceu16, 0xa9ffu16, 0xab27u16, 0xab2fu16, 0xfb37u16, 0xfb3du16, 0xfb3fu16, 0xfb42u16,
|
||||
0xfb45u16, 0xfe53u16, 0xfe67u16, 0xfe75u16, 0xffe7u16,
|
||||
];
|
||||
|
||||
let pkgprint32: [508]u32 = [
|
||||
0x010000u32, 0x01004du32, 0x010050u32, 0x01005du32, 0x010080u32, 0x0100fau32, 0x010100u32, 0x010102u32,
|
||||
0x010107u32, 0x010133u32, 0x010137u32, 0x01019cu32, 0x0101a0u32, 0x0101a0u32, 0x0101d0u32, 0x0101fdu32,
|
||||
0x010280u32, 0x01029cu32, 0x0102a0u32, 0x0102d0u32, 0x0102e0u32, 0x0102fbu32, 0x010300u32, 0x010323u32,
|
||||
0x01032du32, 0x01034au32, 0x010350u32, 0x01037au32, 0x010380u32, 0x0103c3u32, 0x0103c8u32, 0x0103d5u32,
|
||||
0x010400u32, 0x01049du32, 0x0104a0u32, 0x0104a9u32, 0x0104b0u32, 0x0104d3u32, 0x0104d8u32, 0x0104fbu32,
|
||||
0x010500u32, 0x010527u32, 0x010530u32, 0x010563u32, 0x01056fu32, 0x0105bcu32, 0x010600u32, 0x010736u32,
|
||||
0x010740u32, 0x010755u32, 0x010760u32, 0x010767u32, 0x010780u32, 0x0107bau32, 0x010800u32, 0x010805u32,
|
||||
0x010808u32, 0x010838u32, 0x01083cu32, 0x01083cu32, 0x01083fu32, 0x01089eu32, 0x0108a7u32, 0x0108afu32,
|
||||
0x0108e0u32, 0x0108f5u32, 0x0108fbu32, 0x01091bu32, 0x01091fu32, 0x010939u32, 0x01093fu32, 0x01093fu32,
|
||||
0x010980u32, 0x0109b7u32, 0x0109bcu32, 0x0109cfu32, 0x0109d2u32, 0x010a06u32, 0x010a0cu32, 0x010a35u32,
|
||||
0x010a38u32, 0x010a3au32, 0x010a3fu32, 0x010a48u32, 0x010a50u32, 0x010a58u32, 0x010a60u32, 0x010a9fu32,
|
||||
0x010ac0u32, 0x010ae6u32, 0x010aebu32, 0x010af6u32, 0x010b00u32, 0x010b35u32, 0x010b39u32, 0x010b55u32,
|
||||
0x010b58u32, 0x010b72u32, 0x010b78u32, 0x010b91u32, 0x010b99u32, 0x010b9cu32, 0x010ba9u32, 0x010bafu32,
|
||||
0x010c00u32, 0x010c48u32, 0x010c80u32, 0x010cb2u32, 0x010cc0u32, 0x010cf2u32, 0x010cfau32, 0x010d27u32,
|
||||
0x010d30u32, 0x010d39u32, 0x010e60u32, 0x010eadu32, 0x010eb0u32, 0x010eb1u32, 0x010efdu32, 0x010f27u32,
|
||||
0x010f30u32, 0x010f59u32, 0x010f70u32, 0x010f89u32, 0x010fb0u32, 0x010fcbu32, 0x010fe0u32, 0x010ff6u32,
|
||||
0x011000u32, 0x01104du32, 0x011052u32, 0x011075u32, 0x01107fu32, 0x0110c2u32, 0x0110d0u32, 0x0110e8u32,
|
||||
0x0110f0u32, 0x0110f9u32, 0x011100u32, 0x011147u32, 0x011150u32, 0x011176u32, 0x011180u32, 0x0111f4u32,
|
||||
0x011200u32, 0x011241u32, 0x011280u32, 0x0112a9u32, 0x0112b0u32, 0x0112eau32, 0x0112f0u32, 0x0112f9u32,
|
||||
0x011300u32, 0x01130cu32, 0x01130fu32, 0x011310u32, 0x011313u32, 0x011344u32, 0x011347u32, 0x011348u32,
|
||||
0x01134bu32, 0x01134du32, 0x011350u32, 0x011350u32, 0x011357u32, 0x011357u32, 0x01135du32, 0x011363u32,
|
||||
0x011366u32, 0x01136cu32, 0x011370u32, 0x011374u32, 0x011400u32, 0x011461u32, 0x011480u32, 0x0114c7u32,
|
||||
0x0114d0u32, 0x0114d9u32, 0x011580u32, 0x0115b5u32, 0x0115b8u32, 0x0115ddu32, 0x011600u32, 0x011644u32,
|
||||
0x011650u32, 0x011659u32, 0x011660u32, 0x01166cu32, 0x011680u32, 0x0116b9u32, 0x0116c0u32, 0x0116c9u32,
|
||||
0x011700u32, 0x01171au32, 0x01171du32, 0x01172bu32, 0x011730u32, 0x011746u32, 0x011800u32, 0x01183bu32,
|
||||
0x0118a0u32, 0x0118f2u32, 0x0118ffu32, 0x011906u32, 0x011909u32, 0x011909u32, 0x01190cu32, 0x011938u32,
|
||||
0x01193bu32, 0x011946u32, 0x011950u32, 0x011959u32, 0x0119a0u32, 0x0119a7u32, 0x0119aau32, 0x0119d7u32,
|
||||
0x0119dau32, 0x0119e4u32, 0x011a00u32, 0x011a47u32, 0x011a50u32, 0x011aa2u32, 0x011ab0u32, 0x011af8u32,
|
||||
0x011b00u32, 0x011b09u32, 0x011c00u32, 0x011c45u32, 0x011c50u32, 0x011c6cu32, 0x011c70u32, 0x011c8fu32,
|
||||
0x011c92u32, 0x011cb6u32, 0x011d00u32, 0x011d36u32, 0x011d3au32, 0x011d47u32, 0x011d50u32, 0x011d59u32,
|
||||
0x011d60u32, 0x011d98u32, 0x011da0u32, 0x011da9u32, 0x011ee0u32, 0x011ef8u32, 0x011f00u32, 0x011f3au32,
|
||||
0x011f3eu32, 0x011f59u32, 0x011fb0u32, 0x011fb0u32, 0x011fc0u32, 0x011ff1u32, 0x011fffu32, 0x012399u32,
|
||||
0x012400u32, 0x012474u32, 0x012480u32, 0x012543u32, 0x012f90u32, 0x012ff2u32, 0x013000u32, 0x01342fu32,
|
||||
0x013440u32, 0x013455u32, 0x014400u32, 0x014646u32, 0x016800u32, 0x016a38u32, 0x016a40u32, 0x016a69u32,
|
||||
0x016a6eu32, 0x016ac9u32, 0x016ad0u32, 0x016aedu32, 0x016af0u32, 0x016af5u32, 0x016b00u32, 0x016b45u32,
|
||||
0x016b50u32, 0x016b77u32, 0x016b7du32, 0x016b8fu32, 0x016e40u32, 0x016e9au32, 0x016f00u32, 0x016f4au32,
|
||||
0x016f4fu32, 0x016f87u32, 0x016f8fu32, 0x016f9fu32, 0x016fe0u32, 0x016fe4u32, 0x016ff0u32, 0x016ff1u32,
|
||||
0x017000u32, 0x0187f7u32, 0x018800u32, 0x018cd5u32, 0x018d00u32, 0x018d08u32, 0x01aff0u32, 0x01b122u32,
|
||||
0x01b132u32, 0x01b132u32, 0x01b150u32, 0x01b152u32, 0x01b155u32, 0x01b155u32, 0x01b164u32, 0x01b167u32,
|
||||
0x01b170u32, 0x01b2fbu32, 0x01bc00u32, 0x01bc6au32, 0x01bc70u32, 0x01bc7cu32, 0x01bc80u32, 0x01bc88u32,
|
||||
0x01bc90u32, 0x01bc99u32, 0x01bc9cu32, 0x01bc9fu32, 0x01cf00u32, 0x01cf2du32, 0x01cf30u32, 0x01cf46u32,
|
||||
0x01cf50u32, 0x01cfc3u32, 0x01d000u32, 0x01d0f5u32, 0x01d100u32, 0x01d126u32, 0x01d129u32, 0x01d172u32,
|
||||
0x01d17bu32, 0x01d1eau32, 0x01d200u32, 0x01d245u32, 0x01d2c0u32, 0x01d2d3u32, 0x01d2e0u32, 0x01d2f3u32,
|
||||
0x01d300u32, 0x01d356u32, 0x01d360u32, 0x01d378u32, 0x01d400u32, 0x01d49fu32, 0x01d4a2u32, 0x01d4a2u32,
|
||||
0x01d4a5u32, 0x01d4a6u32, 0x01d4a9u32, 0x01d50au32, 0x01d50du32, 0x01d546u32, 0x01d54au32, 0x01d6a5u32,
|
||||
0x01d6a8u32, 0x01d7cbu32, 0x01d7ceu32, 0x01da8bu32, 0x01da9bu32, 0x01daafu32, 0x01df00u32, 0x01df1eu32,
|
||||
0x01df25u32, 0x01df2au32, 0x01e000u32, 0x01e018u32, 0x01e01bu32, 0x01e02au32, 0x01e030u32, 0x01e06du32,
|
||||
0x01e08fu32, 0x01e08fu32, 0x01e100u32, 0x01e12cu32, 0x01e130u32, 0x01e13du32, 0x01e140u32, 0x01e149u32,
|
||||
0x01e14eu32, 0x01e14fu32, 0x01e290u32, 0x01e2aeu32, 0x01e2c0u32, 0x01e2f9u32, 0x01e2ffu32, 0x01e2ffu32,
|
||||
0x01e4d0u32, 0x01e4f9u32, 0x01e7e0u32, 0x01e8c4u32, 0x01e8c7u32, 0x01e8d6u32, 0x01e900u32, 0x01e94bu32,
|
||||
0x01e950u32, 0x01e959u32, 0x01e95eu32, 0x01e95fu32, 0x01ec71u32, 0x01ecb4u32, 0x01ed01u32, 0x01ed3du32,
|
||||
0x01ee00u32, 0x01ee24u32, 0x01ee27u32, 0x01ee3bu32, 0x01ee42u32, 0x01ee42u32, 0x01ee47u32, 0x01ee54u32,
|
||||
0x01ee57u32, 0x01ee64u32, 0x01ee67u32, 0x01ee9bu32, 0x01eea1u32, 0x01eebbu32, 0x01eef0u32, 0x01eef1u32,
|
||||
0x01f000u32, 0x01f02bu32, 0x01f030u32, 0x01f093u32, 0x01f0a0u32, 0x01f0aeu32, 0x01f0b1u32, 0x01f0f5u32,
|
||||
0x01f100u32, 0x01f1adu32, 0x01f1e6u32, 0x01f202u32, 0x01f210u32, 0x01f23bu32, 0x01f240u32, 0x01f248u32,
|
||||
0x01f250u32, 0x01f251u32, 0x01f260u32, 0x01f265u32, 0x01f300u32, 0x01f6d7u32, 0x01f6dcu32, 0x01f6ecu32,
|
||||
0x01f6f0u32, 0x01f6fcu32, 0x01f700u32, 0x01f776u32, 0x01f77bu32, 0x01f7d9u32, 0x01f7e0u32, 0x01f7ebu32,
|
||||
0x01f7f0u32, 0x01f7f0u32, 0x01f800u32, 0x01f80bu32, 0x01f810u32, 0x01f847u32, 0x01f850u32, 0x01f859u32,
|
||||
0x01f860u32, 0x01f887u32, 0x01f890u32, 0x01f8adu32, 0x01f8b0u32, 0x01f8b1u32, 0x01f900u32, 0x01fa53u32,
|
||||
0x01fa60u32, 0x01fa6du32, 0x01fa70u32, 0x01fa7cu32, 0x01fa80u32, 0x01fa88u32, 0x01fa90u32, 0x01fac5u32,
|
||||
0x01faceu32, 0x01fadbu32, 0x01fae0u32, 0x01fae8u32, 0x01faf0u32, 0x01faf8u32, 0x01fb00u32, 0x01fbcau32,
|
||||
0x01fbf0u32, 0x01fbf9u32, 0x020000u32, 0x02a6dfu32, 0x02a700u32, 0x02b739u32, 0x02b740u32, 0x02b81du32,
|
||||
0x02b820u32, 0x02cea1u32, 0x02ceb0u32, 0x02ebe0u32, 0x02f800u32, 0x02fa1du32, 0x030000u32, 0x03134au32,
|
||||
0x031350u32, 0x0323afu32, 0x0e0100u32, 0x0e01efu32,
|
||||
];
|
||||
|
||||
let pkgnotprint32: [112]u16 = [
|
||||
0x000cu16, 0x0027u16, 0x003bu16, 0x003eu16, 0x018fu16, 0x039eu16, 0x057bu16,
|
||||
0x058bu16, 0x0593u16, 0x0596u16, 0x05a2u16, 0x05b2u16, 0x05bau16, 0x0786u16, 0x07b1u16,
|
||||
0x0809u16, 0x0836u16, 0x0856u16, 0x08f3u16, 0x0a04u16, 0x0a14u16, 0x0a18u16, 0x0e7fu16,
|
||||
0x0eaau16, 0x10bdu16, 0x1135u16, 0x11e0u16, 0x1212u16, 0x1287u16, 0x1289u16, 0x128eu16,
|
||||
0x129eu16, 0x1304u16, 0x1329u16, 0x1331u16, 0x1334u16, 0x133au16, 0x145cu16, 0x1914u16,
|
||||
0x1917u16, 0x1936u16, 0x1c09u16, 0x1c37u16, 0x1ca8u16, 0x1d07u16, 0x1d0au16, 0x1d3bu16,
|
||||
0x1d3eu16, 0x1d66u16, 0x1d69u16, 0x1d8fu16, 0x1d92u16, 0x1f11u16, 0x246fu16, 0x6a5fu16,
|
||||
0x6abfu16, 0x6b5au16, 0x6b62u16, 0xaff4u16, 0xaffcu16, 0xafffu16, 0xd455u16, 0xd49du16,
|
||||
0xd4adu16, 0xd4bau16, 0xd4bcu16, 0xd4c4u16, 0xd506u16, 0xd515u16, 0xd51du16, 0xd53au16,
|
||||
0xd53fu16, 0xd545u16, 0xd551u16, 0xdaa0u16, 0xe007u16, 0xe022u16, 0xe025u16, 0xe7e7u16,
|
||||
0xe7ecu16, 0xe7efu16, 0xe7ffu16, 0xee04u16, 0xee20u16, 0xee23u16, 0xee28u16, 0xee33u16,
|
||||
0xee38u16, 0xee3au16, 0xee48u16, 0xee4au16, 0xee4cu16, 0xee50u16, 0xee53u16, 0xee58u16,
|
||||
0xee5au16, 0xee5cu16, 0xee5eu16, 0xee60u16, 0xee63u16, 0xee6bu16, 0xee73u16, 0xee78u16,
|
||||
0xee7du16, 0xee7fu16, 0xee8au16, 0xeea4u16, 0xeeaau16, 0xf0c0u16, 0xf0d0u16, 0xfabeu16,
|
||||
0xfb93u16,
|
||||
];
|
||||
|
||||
fn pkgbsearch16(values: []u16, target: u16) i32 = {
|
||||
let low: i32 = 0;
|
||||
let high: i32 = values.len;
|
||||
for (low < high) {
|
||||
let middle: i32 = low + (high - low) / 2;
|
||||
if (values[middle] < target) { low = middle + 1; }
|
||||
else { high = middle; };
|
||||
};
|
||||
return low;
|
||||
};
|
||||
|
||||
fn pkgbsearch32(values: []u32, target: u32) i32 = {
|
||||
let low: i32 = 0;
|
||||
let high: i32 = values.len;
|
||||
for (low < high) {
|
||||
let middle: i32 = low + (high - low) / 2;
|
||||
if (values[middle] < target) { low = middle + 1; }
|
||||
else { high = middle; };
|
||||
};
|
||||
return low;
|
||||
};
|
||||
|
||||
fn pkgisprint(r: u32) bool = {
|
||||
if (r <= 0xffu32) {
|
||||
if (r >= 0x20u32 && r <= 0x7eu32) { return true; };
|
||||
if (r >= 0xa1u32 && r <= 0xffu32) { return r != 0xadu32; };
|
||||
return false;
|
||||
};
|
||||
if (r < 0x10000u32) {
|
||||
let rr: u16 = r: u16;
|
||||
let i: i32 = pkgbsearch16(pkgprint16, rr);
|
||||
if (i >= pkgprint16.len) { return false; };
|
||||
let start: i32 = i;
|
||||
if (start % 2 != 0) { start -= 1; };
|
||||
if (start + 1 >= pkgprint16.len
|
||||
|| rr < pkgprint16[start] || pkgprint16[start + 1] < rr) {
|
||||
return false;
|
||||
};
|
||||
let excluded: i32 = pkgbsearch16(pkgnotprint16, rr);
|
||||
return excluded >= pkgnotprint16.len
|
||||
|| pkgnotprint16[excluded] != rr;
|
||||
};
|
||||
let i: i32 = pkgbsearch32(pkgprint32, r);
|
||||
if (i >= pkgprint32.len) { return false; };
|
||||
let start: i32 = i;
|
||||
if (start % 2 != 0) { start -= 1; };
|
||||
if (start + 1 >= pkgprint32.len
|
||||
|| r < pkgprint32[start] || pkgprint32[start + 1] < r) {
|
||||
return false;
|
||||
};
|
||||
if (r >= 0x20000u32) { return true; };
|
||||
let rr: u16 = (r - 0x10000u32): u16;
|
||||
let excluded: i32 = pkgbsearch16(pkgnotprint32, rr);
|
||||
return excluded >= pkgnotprint32.len
|
||||
|| pkgnotprint32[excluded] != rr;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -31,6 +31,8 @@ def SEP_LOCAL_IMPORT_PREFIX: str = "__wwlocal";
|
||||
let selfpath: *u8;
|
||||
let sepfatalallocation: bool;
|
||||
|
||||
@symbol("rt_envp") fn rawenvp() **u8;
|
||||
|
||||
// Tool-local (NOT a lib wrapper): messages are built from many
|
||||
// fragments and we route through os.write to avoid libc stdio.
|
||||
// .len replaces the error-prone hand-counted byte literals these sites
|
||||
@@ -77,6 +79,28 @@ fn cstrlen(p: *u8) u64 = {
|
||||
return n;
|
||||
};
|
||||
|
||||
fn rawenvvalue(name: str) *u8 = {
|
||||
let env: **u8 = rawenvp();
|
||||
let i: i32 = 0;
|
||||
for (env[i] != nil) {
|
||||
let entry: *u8 = env[i];
|
||||
let j: i32 = 0;
|
||||
for (j < name.len && entry[j] == name[j]) { j += 1; };
|
||||
if (j == name.len && entry[j] == '=': u8) {
|
||||
return entry + ((j + 1): u64);
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
return nil;
|
||||
};
|
||||
|
||||
fn clipathfits(command: str, flag: str, value: *u8) bool = {
|
||||
if (cstrlen(value) < os.PATH_MAX: u64) { return true; };
|
||||
cerr("ww "); cerr(command); cerr(": "); cerr(flag);
|
||||
cerr(" path is too long\n");
|
||||
return false;
|
||||
};
|
||||
|
||||
// Bridges the driver's argv-style *u8 paths to lib/os entrypoints
|
||||
// (str post-task-#23).
|
||||
fn pathstr(p: *u8) str = {
|
||||
@@ -242,21 +266,39 @@ fn toolpath(selfdir: *u8, envvar: str, name: str) *u8 = {
|
||||
// package.ww roots stay on runsingletest, which is the recursion boundary when
|
||||
// wwtest builds its already-aggregated package binaries.
|
||||
fn execpackagetests(selfdir: *u8, argv: **u8, argc: i32, start: i32,
|
||||
targetindex: i32, resolved: *u8, rootidentity: *u8, adddot: bool) i32 = {
|
||||
let prog: *u8 = joinpathlit(selfdir, "wwtest");
|
||||
match (os.getenv("WW_WWTEST")) {
|
||||
case let p: str => {
|
||||
if (p.len != 0) { prog = owncstr(p); };
|
||||
};
|
||||
case void => void;
|
||||
targetindex: i32, resolved: *u8, rootidentity: *u8, adddot: bool,
|
||||
buildonly: bool) i32 = {
|
||||
let prog: *u8 = rawenvvalue("WW_WWTEST");
|
||||
if (prog == nil || prog[0u64] == 0u8) {
|
||||
prog = sepjoinpathlit(selfdir, "wwtest");
|
||||
if (prog == nil) { return 1; };
|
||||
};
|
||||
|
||||
let cap: i32 = argc - start + 8;
|
||||
let execargv: []*u8 = alloc([], cap: u64)!;
|
||||
execargv.len = cap;
|
||||
if (start < 0 || start > argc || argc - start > SEP_COUNT_MAX - 10) {
|
||||
sepfailsize();
|
||||
return 1;
|
||||
};
|
||||
let cap: i32 = argc - start + 10;
|
||||
let execargv: []*u8;
|
||||
let argvallocation: ([]*u8 | nomem) = sepallocptrs(cap);
|
||||
match (argvallocation) {
|
||||
case let value: []*u8 => { execargv = value; execargv.len = cap; };
|
||||
case nomem => {
|
||||
if (buildonly) {
|
||||
cerr("ww build: cannot allocate package coordinator arguments\n");
|
||||
} else {
|
||||
cerr("ww test: cannot allocate package coordinator arguments\n");
|
||||
};
|
||||
return 1;
|
||||
};
|
||||
};
|
||||
let n: i32 = 0;
|
||||
execargv[n] = prog; n += 1;
|
||||
execargv[n] = "package".ptr; n += 1;
|
||||
if (buildonly) {
|
||||
execargv[n] = "--ww-operation".ptr; n += 1;
|
||||
execargv[n] = "build".ptr; n += 1;
|
||||
};
|
||||
execargv[n] = "--ww-driver".ptr; n += 1;
|
||||
execargv[n] = selfpath; n += 1;
|
||||
if (rootidentity != nil) {
|
||||
@@ -278,14 +320,9 @@ fn execpackagetests(selfdir: *u8, argv: **u8, argc: i32, start: i32,
|
||||
if (adddot && !dotted) { execargv[n] = ".".ptr; n += 1; };
|
||||
execargv[n] = nil;
|
||||
|
||||
let env: []str = os.getenvs();
|
||||
let envp: []*u8 = alloc([], (env.len + 1): u64)!;
|
||||
envp.len = env.len + 1;
|
||||
i = 0;
|
||||
for (i < env.len) { envp[i] = owncstr(env[i]); i += 1; };
|
||||
envp[env.len] = nil;
|
||||
os.execve(pathstr(prog), execargv.ptr, envp.ptr);
|
||||
cerr("ww test: cannot exec package test coordinator\n");
|
||||
os.execve(pathstr(prog), execargv.ptr, rawenvp());
|
||||
if (buildonly) { cerr("ww build: cannot exec package coordinator\n"); }
|
||||
else { cerr("ww test: cannot exec package coordinator\n"); };
|
||||
return 1;
|
||||
};
|
||||
|
||||
@@ -534,6 +571,7 @@ fn dirfileclass(dirpath: *u8, name: *u8, nlen: u64,
|
||||
// nlen<=3 guard kept: a bare ".ww" (len 3) is rejected here but
|
||||
// would pass strings.hassuffix(".ww"); preserves cstage parity.
|
||||
if (nlen <= 3u64) { return 0; };
|
||||
if (name[0] == '.' || name[0] == '_') { return 0; };
|
||||
let s: str;
|
||||
s.ptr = name;
|
||||
s.len = nlen: i32;
|
||||
@@ -545,13 +583,27 @@ fn dirfileclass(dirpath: *u8, name: *u8, nlen: u64,
|
||||
let fi: os.filestat;
|
||||
let sr: (void | os.oserror) = os.lstat(&fi, pathstr(source));
|
||||
let regular: bool = false;
|
||||
let directory: bool = false;
|
||||
match (sr) {
|
||||
case void => {
|
||||
let t: u32 = (fi.mode: u32) & 61440u32;
|
||||
if (t == os.mode.REG: u32) { regular = true; };
|
||||
if (t == os.mode.REG: u32) { regular = true; }
|
||||
else if (t == os.mode.LINK: u32) {
|
||||
let target: os.filestat;
|
||||
match (os.stat(&target, pathstr(source))) {
|
||||
case void => {
|
||||
let tt: u32 = (target.mode: u32) & 61440u32;
|
||||
if (tt == os.mode.REG: u32) { regular = true; };
|
||||
if (tt == os.mode.DIR: u32) { directory = true; };
|
||||
};
|
||||
case let e: os.oserror => void;
|
||||
};
|
||||
};
|
||||
};
|
||||
case let e: os.oserror => void;
|
||||
};
|
||||
// go/build ignores a source-shaped symlink to a directory.
|
||||
if (directory) { return 0; };
|
||||
if (!regular) {
|
||||
cerr("ww: "); cerr(pathstr(source));
|
||||
cerr(": package source is not a regular file\n");
|
||||
@@ -4265,6 +4317,14 @@ fn validatepackageoutputpath(out: *u8) i32 = {
|
||||
return 0;
|
||||
};
|
||||
|
||||
fn validatecommandoutputpath(out: *u8) i32 = {
|
||||
if (out == nil || cstrlen(out) + 1u64 > os.PATH_MAX: u64) {
|
||||
cerr("ww: command output path is too long\n");
|
||||
return -1;
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
|
||||
// The stamp pins the non-content build inputs a unit compare cannot see:
|
||||
// the -T/-S/root-action shape of the producer pass and the artifact protocol
|
||||
// revision (bump "fmt" when the unit/archive/commit format changes).
|
||||
@@ -4374,6 +4434,84 @@ fn invalidateworkdirunits(scratch: *u8) i32 = {
|
||||
return rc;
|
||||
};
|
||||
|
||||
type sepcreateddirs = struct {
|
||||
path: [4096]u8,
|
||||
offset: [2048]u16,
|
||||
n: i32,
|
||||
};
|
||||
|
||||
fn seprollbackdirs(created: *sepcreateddirs) void = {
|
||||
for (created.n > 0) {
|
||||
created.n -= 1;
|
||||
let at: u64 = created.offset[created.n]: u64;
|
||||
let saved: u8 = created.path[at];
|
||||
created.path[at] = 0u8;
|
||||
let ignored: i32 = os.rmdir(pathstr(&created.path[0]));
|
||||
created.path[at] = saved;
|
||||
};
|
||||
};
|
||||
|
||||
// Keep the prefixes created after semantic preflight separately from
|
||||
// pre-existing caller state so a later setup failure can reclaim only them.
|
||||
fn sepmkdirsrecord(path: *u8, mode: i32, created: *sepcreateddirs) i32 = {
|
||||
created.n = 0;
|
||||
let n: u64 = cstrlen(path);
|
||||
if (n == 0u64 || n >= os.PATH_MAX: u64) { return -1; };
|
||||
let buf: [4096]u8;
|
||||
bytecpy(&buf[0], path, n + 1u64);
|
||||
for (n > 1u64 && buf[n - 1u64] == 47u8) {
|
||||
n -= 1u64;
|
||||
buf[n] = 0u8;
|
||||
};
|
||||
bytecpy(&created.path[0], &buf[0], n + 1u64);
|
||||
let i: u64 = 0u64;
|
||||
if (buf[0] == 47u8) { i = 1u64; };
|
||||
for (i <= n) {
|
||||
if (buf[i] != 47u8 && buf[i] != 0u8) {
|
||||
i += 1u64;
|
||||
continue;
|
||||
};
|
||||
let saved: u8 = buf[i];
|
||||
buf[i] = 0u8;
|
||||
if (buf[0] != 0u8) {
|
||||
let fi: os.filestat;
|
||||
let missing: bool = false;
|
||||
match (os.stat(&fi, pathstr(&buf[0]))) {
|
||||
case void => {
|
||||
let typ: u32 = (fi.mode: u32) & 61440u32;
|
||||
if (typ != os.mode.DIR: u32) {
|
||||
buf[i] = saved;
|
||||
seprollbackdirs(created);
|
||||
return -1;
|
||||
};
|
||||
};
|
||||
case let e: os.oserror => {
|
||||
if ((e: i64) == -2i64) { missing = true; }
|
||||
else {
|
||||
buf[i] = saved;
|
||||
seprollbackdirs(created);
|
||||
return -1;
|
||||
};
|
||||
};
|
||||
};
|
||||
if (missing) {
|
||||
if (created.n >= 2048
|
||||
|| os.mkdir(pathstr(&buf[0]), mode) != 0) {
|
||||
buf[i] = saved;
|
||||
seprollbackdirs(created);
|
||||
return -1;
|
||||
};
|
||||
created.offset[created.n] = i: u16;
|
||||
created.n += 1;
|
||||
};
|
||||
};
|
||||
buf[i] = saved;
|
||||
if (saved == 0u8) { break; };
|
||||
i += 1u64;
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
|
||||
// cerrpath — the "ww: <head><path>\n" diagnostic shape shared by the
|
||||
// workdir error sites; byte-identical wording to the cstage twin's
|
||||
// fprintf(..., "%s", path) forms.
|
||||
@@ -4387,7 +4525,8 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
out: *u8, objstem: *u8, incs: *u8, lf: *lflags,
|
||||
publishpackage: i32, requirecommand: i32, istest: i32,
|
||||
products: *sepproduct, nproducts: i32, emitasm: i32,
|
||||
workdir: *u8, scratchout: **u8,
|
||||
workdir: *u8, createworkdir: bool, createoutputdir: *u8,
|
||||
scratchout: **u8,
|
||||
graphout: **sepgraph) i32 = {
|
||||
sepfatalallocation = false;
|
||||
if (nproducts < 1) { return 1; };
|
||||
@@ -4461,6 +4600,7 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
let effstem: *u8 = stem;
|
||||
if (objstem != nil) { effstem = objstem; };
|
||||
let warm: bool = false;
|
||||
let workdirexists: bool = false;
|
||||
if (workdir != nil) {
|
||||
if (workdir[0u64] != 0u8) { warm = true; };
|
||||
};
|
||||
@@ -4468,23 +4608,38 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
if (warm) {
|
||||
let wfi: os.filestat;
|
||||
let wok: bool = false;
|
||||
let missing: bool = false;
|
||||
match (os.stat(&wfi, pathstr(workdir))) {
|
||||
case void => {
|
||||
let wt: u32 = (wfi.mode: u32) & 61440u32; // S_IFMT
|
||||
if (wt == os.mode.DIR: u32) { wok = true; };
|
||||
if (wt == os.mode.DIR: u32) {
|
||||
wok = true; workdirexists = true;
|
||||
};
|
||||
};
|
||||
case let e: os.oserror => void;
|
||||
case let e: os.oserror => {
|
||||
if ((e: i64) == -2i64) { missing = true; };
|
||||
};
|
||||
if (!wok) {
|
||||
};
|
||||
if (!wok && !(createworkdir && missing)) {
|
||||
cerrpath("ww: workdir ", workdir,
|
||||
" is not a directory\n");
|
||||
return 1;
|
||||
};
|
||||
if (cstrlen(workdir) + 1u64 > os.PATH_MAX: u64) {
|
||||
cerr("ww: workdir path is too long\n");
|
||||
return 1;
|
||||
};
|
||||
// The workdir is caller-owned and persistent: no acquisition,
|
||||
// no refusal, and scratchout stays nil so the wrapper never
|
||||
// cleans it.
|
||||
scratch = workdir;
|
||||
} else {
|
||||
let suffix: u64 = ".sepwork".len: u64 + 1u64;
|
||||
if (suffix > os.PATH_MAX: u64
|
||||
|| cstrlen(effstem) > os.PATH_MAX: u64 - suffix) {
|
||||
cerr("ww: scratch path is too long\n");
|
||||
return 1;
|
||||
};
|
||||
scratch = sepappendlit(effstem, ".sepwork");
|
||||
if (scratch == nil) { return 1; };
|
||||
};
|
||||
@@ -4500,6 +4655,12 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
cerrpath("ww: cannot read driver identity ", selfpath, "\n");
|
||||
return 1;
|
||||
};
|
||||
let toolsuffix: u64 = "/.wwtool.stamp".len: u64 + 1u64;
|
||||
if (toolsuffix > os.PATH_MAX: u64
|
||||
|| cstrlen(scratch) > os.PATH_MAX: u64 - toolsuffix) {
|
||||
cerr("ww: workdir path is too long\n");
|
||||
return 1;
|
||||
};
|
||||
toolw = sepjoinpathlit(scratch, ".wwtool.ww");
|
||||
toolc = sepjoinpathlit(scratch, ".wwtool.w6c");
|
||||
toola = sepjoinpathlit(scratch, ".wwtool.w6a");
|
||||
@@ -4753,11 +4914,21 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
producti += 1;
|
||||
};
|
||||
};
|
||||
let rootpackage: bool = istest == 0
|
||||
producti = 0;
|
||||
for (producti < nproducts) {
|
||||
let root: i32 = products[producti].root;
|
||||
if (!g.pkg[root].failed && seprootiscommand(&g.pkg[root])
|
||||
&& validatecommandoutputpath(products[producti].out) < 0) {
|
||||
return 1;
|
||||
};
|
||||
producti += 1;
|
||||
};
|
||||
let rootpackage: bool = istest == 0 && nproducts == 1
|
||||
&& !g.pkg[products[0].root].failed
|
||||
&& !seprootiscommand(&g.pkg[products[0].root]);
|
||||
if (sepvalidateartifactpaths(g, scratch) < 0) { return 1; };
|
||||
if (warm && sepvalidateworkdirowners(g, scratch) < 0) { return 1; };
|
||||
if (warm && workdirexists
|
||||
&& sepvalidateworkdirowners(g, scratch) < 0) { return 1; };
|
||||
let ci: i32 = 0;
|
||||
let order: []i32;
|
||||
let stack: []i32;
|
||||
@@ -4836,9 +5007,30 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
if (!viableproduct) { return 1; };
|
||||
// Source-derived resolution and contextual legality are complete before
|
||||
// coordinator completion markers or persistent vouchers are changed.
|
||||
let createdoutput: sepcreateddirs;
|
||||
let createdwork: sepcreateddirs;
|
||||
createdoutput.n = 0;
|
||||
createdwork.n = 0;
|
||||
if (createoutputdir != nil
|
||||
&& sepmkdirsrecord(createoutputdir, 448, &createdoutput) != 0) {
|
||||
cerrpath("ww: cannot create build output directory ",
|
||||
createoutputdir, "\n");
|
||||
return 1;
|
||||
};
|
||||
if (warm && !workdirexists) {
|
||||
if (!createworkdir
|
||||
|| sepmkdirsrecord(scratch, 448, &createdwork) != 0) {
|
||||
cerrpath("ww: workdir ", scratch, " is not a directory\n");
|
||||
seprollbackdirs(&createdoutput);
|
||||
return 1;
|
||||
};
|
||||
workdirexists = true;
|
||||
};
|
||||
if (!warm) {
|
||||
if (os.mkdir(pathstr(scratch), 493i32) != 0) {
|
||||
cerr("ww: cannot create scratch\n");
|
||||
cerrpath("ww: cannot create scratch ", scratch, "\n");
|
||||
seprollbackdirs(&createdwork);
|
||||
seprollbackdirs(&createdoutput);
|
||||
return 1;
|
||||
};
|
||||
// The wrapper owns only the directory this invocation acquired.
|
||||
@@ -5179,7 +5371,22 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
};
|
||||
};
|
||||
};
|
||||
if (emitasm != 0) { if (anyfailed) { return 1; }; return 0; };
|
||||
if (emitasm != 0) {
|
||||
let producti: i32 = 0;
|
||||
for (producti < nproducts) {
|
||||
let root: i32 = products[producti].root;
|
||||
if (g.pkg[root].failed) {
|
||||
anyfailed = true;
|
||||
} else if (recordproductstatus(products[producti].status) != 0) {
|
||||
cerr("ww: cannot record package-build product\n");
|
||||
g.pkg[root].failed = true;
|
||||
anyfailed = true;
|
||||
};
|
||||
producti += 1;
|
||||
};
|
||||
if (anyfailed) { return 1; };
|
||||
return 0;
|
||||
};
|
||||
if (rootpackage) {
|
||||
let root: i32 = products[0].root;
|
||||
if (g.pkg[root].failed) { return 1; };
|
||||
@@ -5196,6 +5403,10 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
return 1;
|
||||
};
|
||||
};
|
||||
if (recordproductstatus(products[0].status) != 0) {
|
||||
cerr("ww: cannot record package-build product\n");
|
||||
return 1;
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
|
||||
@@ -5220,6 +5431,15 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
producti += 1;
|
||||
continue;
|
||||
};
|
||||
if (istest == 0 && !seprootiscommand(&g.pkg[root])) {
|
||||
if (recordproductstatus(products[producti].status) != 0) {
|
||||
cerr("ww: cannot record package-build product\n");
|
||||
g.pkg[root].failed = true;
|
||||
anyfailed = true;
|
||||
};
|
||||
producti += 1;
|
||||
continue;
|
||||
};
|
||||
ci = 0;
|
||||
for (ci < g.n) { g.pkg[ci].color = 0; ci += 1; };
|
||||
let linkorder: []i32;
|
||||
@@ -5369,7 +5589,7 @@ fn buildonesep(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
product.support = -1;
|
||||
let r: i32 = buildonesepimpl(selfdir, src, entryisdir, out, objstem,
|
||||
incs, lf, publishpackage, requirecommand, istest, &product, 1,
|
||||
emitasm, workdir, &scratch, &g);
|
||||
emitasm, workdir, false, nil, &scratch, &g);
|
||||
sepgraphfree(g);
|
||||
if (keepscratch == 0 && scratch != nil) {
|
||||
if (cstrendswithlit(scratch, ".sepwork")) {
|
||||
@@ -5398,20 +5618,21 @@ fn buildonesep(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
// Build every selected directory/variant root inside one command-owned package
|
||||
// universe. The first output owns the shared cold sepwork tree.
|
||||
fn buildpackagetests(selfdir: *u8, src: *u8, rootidentity: *u8,
|
||||
incs: *u8, workdir: *u8, products: *sepproduct, nproducts: i32) i32 = {
|
||||
incs: *u8, workdir: *u8, products: *sepproduct, nproducts: i32,
|
||||
istest: i32, publishpackage: i32, lf: *lflags, emitasm: i32,
|
||||
createworkdir: bool, createoutputdir: *u8) i32 = {
|
||||
let scratch: *u8 = nil;
|
||||
let g: *sepgraph = nil;
|
||||
let lf: lflags;
|
||||
lf.libdirs = nil; lf.nlibdirs = 0;
|
||||
lf.libs = nil; lf.nlibs = 0;
|
||||
let i: i32 = 0;
|
||||
for (i < nproducts) {
|
||||
products[i].identity = rootidentity;
|
||||
i += 1;
|
||||
};
|
||||
let r: i32 = buildonesepimpl(selfdir, src, 1,
|
||||
products[0].out, products[0].out, incs, &lf, 0, 0, 1,
|
||||
products, nproducts, 0, workdir, &scratch, &g);
|
||||
products[0].out, products[0].out, incs, lf,
|
||||
publishpackage, 0, istest,
|
||||
products, nproducts, emitasm, workdir, createworkdir,
|
||||
createoutputdir, &scratch, &g);
|
||||
sepgraphfree(g);
|
||||
return r;
|
||||
};
|
||||
@@ -5507,7 +5728,7 @@ fn resolvemodule(selfdir: *u8, name: *u8, incs: *u8, isdir: *i32) *u8 = {
|
||||
};
|
||||
|
||||
fn writeusage(fd: i32) void = {
|
||||
let s: str = "usage: ww [-V] <subcommand> [args...]\n -V print version and exit\n build [-S] [-w DIR] [-I DIR] [-o FILE] [path] build a local package graph\n run [path] ... build then exec, passing extra args to the program\n test [-S -o STEM] [-w DIR] [options] [path] build/run tests; -S emits package asm\n version print version and exit\n\n path forms:\n foo.ww literal file\n foo search cwd, -I dirs, then the source library for foo.ww or foo/\n lib/foo directory: build its package sources\n -o publishes a non-main archive FILE + FILE.wwi\n lib/... every package under lib, recursively (test only)\n . build the cwd's <basename>.ww\n";
|
||||
let s: str = "usage: ww [-V] <subcommand> [args...]\n -V print version and exit\n build [-S] [-w DIR] [-I DIR] [-o FILE] [path ...] build local package graphs\n run [path] ... build then exec, passing extra args to the program\n test [-S -o STEM] [-w DIR] [options] [path ...] build/run tests; -S emits package asm\n version print version and exit\n\n path forms:\n foo.ww literal file\n foo search cwd, -I dirs, then the source library for foo.ww or foo/\n lib/foo directory: build its package sources\n -o publishes a non-main archive FILE + FILE.wwi\n lib/... every eligible package under lib, recursively\n . build the cwd's <basename>.ww\n";
|
||||
os.write(fd, s.ptr, s.len: u64);
|
||||
};
|
||||
|
||||
@@ -5548,6 +5769,8 @@ fn defaultoutpath(src: *u8) *u8 = {
|
||||
|
||||
fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
let src: *u8 = nil;
|
||||
let srcindex: i32 = -1;
|
||||
let multipleroots: bool = false;
|
||||
let outflag: *u8 = nil; // -o target (binary + intermediate stem); T3
|
||||
let workdir: *u8 = nil; // -w persistent package-artifact workdir
|
||||
let emitasm: i32 = 0;
|
||||
@@ -5564,18 +5787,19 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
cstrseal(incs.ptr, 0u64);
|
||||
|
||||
let maxlflags: i32 = 32;
|
||||
let libdirs: []*u8;
|
||||
if (!sepmakeptrs(maxlflags, &libdirs)) { return 1; };
|
||||
let libdirs: [32]*u8;
|
||||
let nlibdirs: i32 = 0;
|
||||
let libs: []*u8;
|
||||
if (!sepmakeptrs(maxlflags, &libs)) { return 1; };
|
||||
let libs: [32]*u8;
|
||||
let nlibs: i32 = 0;
|
||||
|
||||
let i: i32 = start;
|
||||
for (i < argc) {
|
||||
let p: *u8 = argv[i];
|
||||
if (p[0u64] == 45u8) { // '-'
|
||||
if (cstreqlit(p, "-S")) {
|
||||
if (cstreqlit(p, "--")) {
|
||||
multipleroots = true;
|
||||
break;
|
||||
} else { if (cstreqlit(p, "-S")) {
|
||||
emitasm = 1;
|
||||
} else { if (p[1u64] == 73u8) { // '-I'
|
||||
let dir: *u8 = nil;
|
||||
@@ -5632,17 +5856,18 @@ 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;
|
||||
if (p[2u64] != 0u8) {
|
||||
outflag = p + 2u64;
|
||||
} else {
|
||||
if (i + 1 >= argc) {
|
||||
cerr("ww build: -o needs an argument\n");
|
||||
return 2;
|
||||
};
|
||||
i += 1;
|
||||
outflag = argv[i];
|
||||
};
|
||||
} 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 {
|
||||
@@ -5651,14 +5876,21 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
return 2;
|
||||
};
|
||||
i += 1;
|
||||
workdir = argv[i];
|
||||
};
|
||||
workdir = argv[i];
|
||||
};
|
||||
if (!clipathfits("build", "-w", workdir)) { return 2; };
|
||||
} else {
|
||||
cerr("ww build: unknown flag\n");
|
||||
return 2;
|
||||
}; }; }; }; }; };
|
||||
}; }; }; }; }; }; };
|
||||
} else {
|
||||
if (src == nil) { src = p; };
|
||||
if (src == nil) {
|
||||
src = p;
|
||||
srcindex = i;
|
||||
i += 1;
|
||||
if (i < argc) { multipleroots = true; };
|
||||
break;
|
||||
} else { multipleroots = true; break; };
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
@@ -5667,6 +5899,10 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
let dot: [2]u8 = ['.': u8, 0u8];
|
||||
src = &dot[0];
|
||||
};
|
||||
if (multipleroots || strings.contains(pathstr(src), "...")) {
|
||||
return execpackagetests(selfdir, argv, argc, start, srcindex,
|
||||
nil, nil, false, true);
|
||||
};
|
||||
let requestedliteral: bool = false;
|
||||
let requestedstat: os.filestat;
|
||||
match (os.stat(&requestedstat, pathstr(src))) {
|
||||
@@ -5704,9 +5940,9 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
out = defaultoutpath(resolved);
|
||||
}; };
|
||||
let lf: lflags;
|
||||
lf.libdirs = libdirs.ptr;
|
||||
lf.libdirs = &libdirs[0];
|
||||
lf.nlibdirs = nlibdirs;
|
||||
lf.libs = libs.ptr;
|
||||
lf.libs = &libs[0];
|
||||
lf.nlibs = nlibs;
|
||||
let rootidentity: *u8 = nil;
|
||||
if (!requestedliteral && isdir != 0) { rootidentity = src; };
|
||||
@@ -6085,6 +6321,18 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
let requestidentity: *u8 = nil;
|
||||
let products: []sepproduct;
|
||||
let packageopts: bool = false;
|
||||
let packagebuild: bool = false;
|
||||
let packagepublish: bool = false;
|
||||
let packagecreateworkdir: bool = false;
|
||||
let packagecreateoutputdir: *u8 = nil;
|
||||
let maxpackagelflags: i32 = 32;
|
||||
let packagelibdirs: [32]*u8;
|
||||
let packagelibs: [32]*u8;
|
||||
let packagelinks: lflags;
|
||||
packagelinks.libdirs = &packagelibdirs[0];
|
||||
packagelinks.nlibdirs = 0;
|
||||
packagelinks.libs = &packagelibs[0];
|
||||
packagelinks.nlibs = 0;
|
||||
let afterdash: bool = false;
|
||||
let i: i32 = start;
|
||||
for (i < argc) {
|
||||
@@ -6105,6 +6353,44 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
i += 2;
|
||||
continue;
|
||||
};
|
||||
if (cstreqlit(p, "--ww-package-build")) {
|
||||
if (packagebuild) {
|
||||
cerr("ww test: invalid --ww-package-build\n");
|
||||
return 2;
|
||||
};
|
||||
packagebuild = true;
|
||||
compileonly = 1;
|
||||
i += 1;
|
||||
continue;
|
||||
};
|
||||
if (cstreqlit(p, "--ww-package-publish")) {
|
||||
if (packagepublish) {
|
||||
cerr("ww test: invalid --ww-package-publish\n");
|
||||
return 2;
|
||||
};
|
||||
packagepublish = true;
|
||||
i += 1;
|
||||
continue;
|
||||
};
|
||||
if (cstreqlit(p, "--ww-create-workdir")) {
|
||||
if (packagecreateworkdir) {
|
||||
cerr("ww test: invalid --ww-create-workdir\n");
|
||||
return 2;
|
||||
};
|
||||
packagecreateworkdir = true;
|
||||
i += 1;
|
||||
continue;
|
||||
};
|
||||
if (cstreqlit(p, "--ww-create-output-dir")) {
|
||||
if (i + 1 >= argc || packagecreateoutputdir != nil
|
||||
|| argv[i + 1][0u64] == 0u8) {
|
||||
cerr("ww test: invalid --ww-create-output-dir\n");
|
||||
return 2;
|
||||
};
|
||||
packagecreateoutputdir = argv[i + 1];
|
||||
i += 2;
|
||||
continue;
|
||||
};
|
||||
if (cstreqlit(p, "--ww-package-test")) {
|
||||
if (i + 5 >= argc) {
|
||||
cerr("ww test: --ww-package-test needs kind, package, directory, output, and status\n");
|
||||
@@ -6178,9 +6464,49 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
};
|
||||
if (cstreqlit(p, "-c")) { compileonly = 1; i += 1; continue; };
|
||||
if (cstreqlit(p, "-S")) { emitasm = 1; i += 1; continue; };
|
||||
if (cstreqlit(p, "-list")) {
|
||||
if (!packagebuild && cstreqlit(p, "-list")) {
|
||||
packageopts = true; i += 1; continue;
|
||||
};
|
||||
if (packagebuild && p[1u64] == 76u8) { // '-L'
|
||||
let dir: *u8 = nil;
|
||||
if (p[2u64] != 0u8) {
|
||||
dir = p + 2u64;
|
||||
} else {
|
||||
if (i + 1 >= argc) {
|
||||
cerr("ww test: -L needs an argument\n");
|
||||
return 2;
|
||||
};
|
||||
i += 1;
|
||||
dir = argv[i];
|
||||
};
|
||||
if (packagelinks.nlibdirs >= maxpackagelflags) {
|
||||
cerr("ww test: too many -L\n");
|
||||
return 2;
|
||||
};
|
||||
packagelibdirs[packagelinks.nlibdirs] = dir;
|
||||
packagelinks.nlibdirs += 1;
|
||||
i += 1; continue;
|
||||
};
|
||||
if (packagebuild && p[1u64] == 108u8) { // '-l'
|
||||
let name: *u8 = nil;
|
||||
if (p[2u64] != 0u8) {
|
||||
name = p + 2u64;
|
||||
} else {
|
||||
if (i + 1 >= argc) {
|
||||
cerr("ww test: -l needs an argument\n");
|
||||
return 2;
|
||||
};
|
||||
i += 1;
|
||||
name = argv[i];
|
||||
};
|
||||
if (packagelinks.nlibs >= maxpackagelflags) {
|
||||
cerr("ww test: too many -l\n");
|
||||
return 2;
|
||||
};
|
||||
packagelibs[packagelinks.nlibs] = name;
|
||||
packagelinks.nlibs += 1;
|
||||
i += 1; continue;
|
||||
};
|
||||
if (cstreqlit(p, "-j") || cstreqlit(p, "-run")
|
||||
|| cstreqlit(p, "-filter")) {
|
||||
if (i + 1 >= argc) {
|
||||
@@ -6203,9 +6529,10 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
return 2;
|
||||
};
|
||||
i += 1;
|
||||
outstem = argv[i];
|
||||
};
|
||||
i += 1; continue;
|
||||
outstem = argv[i];
|
||||
};
|
||||
if (!clipathfits("test", "-o", outstem)) { return 2; };
|
||||
i += 1; continue;
|
||||
};
|
||||
if (p[1u64] == 119u8) { // '-w'
|
||||
if (p[2u64] != 0u8) {
|
||||
@@ -6216,8 +6543,9 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
return 2;
|
||||
};
|
||||
i += 1;
|
||||
workdir = argv[i];
|
||||
};
|
||||
workdir = argv[i];
|
||||
};
|
||||
if (!clipathfits("test", "-w", workdir)) { return 2; };
|
||||
i += 1; continue;
|
||||
};
|
||||
cerr("ww test: unknown flag\n"); return 2;
|
||||
@@ -6231,7 +6559,7 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
let dot: [2]u8 = ['.': u8, 0u8];
|
||||
target = &dot[0];
|
||||
};
|
||||
if (emitasm != 0 && outstem == nil) {
|
||||
if (emitasm != 0 && outstem == nil && products.len == 0) {
|
||||
cerr("ww test: -S needs -o\n");
|
||||
return 2;
|
||||
};
|
||||
@@ -6267,22 +6595,82 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
cerr("ww test: package-test variant rejects package options\n");
|
||||
return 2;
|
||||
};
|
||||
if (packagebuild && products.len == 0) {
|
||||
cerr("ww test: --ww-package-build needs products\n");
|
||||
return 2;
|
||||
};
|
||||
if (packagepublish && (!packagebuild || products.len != 1)) {
|
||||
cerr("ww test: invalid --ww-package-publish\n");
|
||||
return 2;
|
||||
};
|
||||
if (packagecreateoutputdir != nil && !packagebuild) {
|
||||
cerr("ww test: invalid private directory creation\n");
|
||||
return 2;
|
||||
};
|
||||
if (packagecreateworkdir && products.len == 0) {
|
||||
cerr("ww test: invalid private directory creation\n");
|
||||
return 2;
|
||||
};
|
||||
if (packagecreateworkdir && workdir == nil) {
|
||||
cerr("ww test: --ww-create-workdir needs -w\n");
|
||||
return 2;
|
||||
};
|
||||
if (!packagebuild && (packagelinks.nlibdirs != 0
|
||||
|| packagelinks.nlibs != 0)) {
|
||||
cerr("ww test: unknown flag\n");
|
||||
return 2;
|
||||
};
|
||||
if (packagebuild) {
|
||||
producti = 0;
|
||||
for (producti < products.len) {
|
||||
if (products[producti].variant != SEP_VARIANT_PRODUCTION) {
|
||||
cerr("ww test: package-build products must be production\n");
|
||||
return 2;
|
||||
};
|
||||
producti += 1;
|
||||
};
|
||||
};
|
||||
if (patarg != nil) {
|
||||
let first: os.filestat;
|
||||
let firstregular: bool = false;
|
||||
let firstfound: bool = false;
|
||||
match (os.stat(&first, pathstr(target))) {
|
||||
case void => {
|
||||
firstfound = true;
|
||||
firstregular = (((first.mode: u32) & 61440u32)
|
||||
== (os.mode.REG: u32));
|
||||
};
|
||||
case let e: os.oserror => void;
|
||||
};
|
||||
if (!firstregular) {
|
||||
let firstresolved: *u8 = nil;
|
||||
let firstisdir: i32 = 0;
|
||||
if (!firstfound) {
|
||||
firstresolved = resolvemodule(selfdir, target, incs.ptr,
|
||||
&firstisdir);
|
||||
};
|
||||
if (firstfound || firstresolved == nil || firstisdir != 0) {
|
||||
let replacement: *u8 = nil;
|
||||
let identity: *u8 = requestidentity;
|
||||
if (firstisdir != 0) {
|
||||
replacement = firstresolved;
|
||||
identity = target;
|
||||
};
|
||||
return execpackagetests(selfdir, argv, argc, start,
|
||||
targetindex, replacement, identity, false, false);
|
||||
};
|
||||
// A logical import resolving to one source retains patarg as its
|
||||
// historical test-name filter and follows the single-file path.
|
||||
};
|
||||
};
|
||||
if (products.len != 0 && outstem != nil) {
|
||||
cerr("ww test: package-test products reject -o\n");
|
||||
return 2;
|
||||
};
|
||||
|
||||
// Go's ./... form: a trailing "..." element is a package-tree
|
||||
// request for the coordinator, never a literal path — recognized
|
||||
// before stat, with the directory-mode rejects.
|
||||
let tlen: u64 = cstrlen(target);
|
||||
let istree: bool = cstreqlit(target, "...");
|
||||
if (!istree && tlen >= 4u64) {
|
||||
istree = target[tlen - 4u64] == '/'
|
||||
&& target[tlen - 3u64] == '.'
|
||||
&& target[tlen - 2u64] == '.'
|
||||
&& target[tlen - 1u64] == '.';
|
||||
};
|
||||
// A local spelling containing "..." enters request selection before
|
||||
// literal-path or logical-import resolution.
|
||||
let istree: bool = strings.contains(pathstr(target), "...");
|
||||
if (istree) {
|
||||
if (products.len != 0) {
|
||||
cerr("ww test: package-test variant needs one directory\n");
|
||||
@@ -6298,14 +6686,10 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
cerr("ww test: -o needs -c for a package target\n");
|
||||
return 2;
|
||||
};
|
||||
if (patarg != nil) {
|
||||
cerr("ww test: pattern needs a single test file\n");
|
||||
return 2;
|
||||
};
|
||||
// -w forwards: the coordinator keys one persistent driver workdir
|
||||
// for the complete selected test request.
|
||||
// -w forwards one caller-owned semantic-action store shared by
|
||||
// the complete selected package universe.
|
||||
return execpackagetests(selfdir, argv, argc, start,
|
||||
targetindex, nil, nil, false);
|
||||
targetindex, nil, nil, false, false);
|
||||
};
|
||||
|
||||
let resolved: *u8 = target;
|
||||
@@ -6345,7 +6729,7 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
emitasm, outstem, workdir, patarg);
|
||||
};
|
||||
|
||||
if (emitasm != 0) {
|
||||
if (emitasm != 0 && products.len == 0) {
|
||||
cerr("ww test: -S needs a single test file\n");
|
||||
return 2;
|
||||
};
|
||||
@@ -6353,23 +6737,25 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
cerr("ww test: -o needs -c for a package target\n");
|
||||
return 2;
|
||||
};
|
||||
if (patarg != nil) {
|
||||
cerr("ww test: pattern needs a single test file\n");
|
||||
return 2;
|
||||
};
|
||||
if (products.len != 0) {
|
||||
if (compileonly == 0) {
|
||||
cerr("ww test: package-test products need -c\n");
|
||||
return 2;
|
||||
};
|
||||
let packagemode: i32 = 1;
|
||||
if (packagebuild) { packagemode = 0; };
|
||||
let publishmode: i32 = 0;
|
||||
if (packagepublish) { publishmode = 1; };
|
||||
return buildpackagetests(selfdir, resolved, rootidentity,
|
||||
incs.ptr, workdir,
|
||||
products.ptr, products.len);
|
||||
products.ptr, products.len, packagemode, publishmode,
|
||||
&packagelinks, emitasm, packagecreateworkdir,
|
||||
packagecreateoutputdir);
|
||||
};
|
||||
let replacement: *u8 = nil;
|
||||
if (resolved != target) { replacement = resolved; };
|
||||
return execpackagetests(selfdir, argv, argc, start, targetindex,
|
||||
replacement, rootidentity, targetindex < 0);
|
||||
replacement, rootidentity, targetindex < 0, false);
|
||||
};
|
||||
|
||||
export fn main(argc: i32, argv: **u8) i32 = {
|
||||
|
||||
Reference in New Issue
Block a user