ww test: retain directory test binaries like Go
This commit is contained in:
105
cmd/ww/main.c
105
cmd/ww/main.c
@@ -13,6 +13,7 @@
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
@@ -1300,6 +1301,7 @@ struct sepproduct {
|
||||
const char *internal_package;
|
||||
const char *external_package;
|
||||
const char *status;
|
||||
const char *publish; /* optional retained test executable */
|
||||
const char *artifact;
|
||||
int variant;
|
||||
int directory_product;
|
||||
@@ -1312,6 +1314,7 @@ struct sepproduct {
|
||||
int pxtest;
|
||||
int support; /* direct generated-main support action, or -1 */
|
||||
char *stage_out; /* request-private linked/published output */
|
||||
char *stage_publish; /* request-private retained executable copy */
|
||||
char *stage_iface; /* request-private published package interface */
|
||||
char *stage_status; /* request-private completion marker */
|
||||
};
|
||||
@@ -4932,6 +4935,34 @@ copy_file_stage(const char *src, const char *dst)
|
||||
return bad ? -1 : 0;
|
||||
}
|
||||
|
||||
/* Go's BuildInstallFunc installs linked test binaries with 0777 filtered by
|
||||
* the caller's umask. Keep the retained copy byte-identical to the temporary
|
||||
* runnable while giving the new staging inode that executable mode. */
|
||||
static int
|
||||
copy_executable_stage(const char *src, const char *dst)
|
||||
{
|
||||
FILE *in = fopen(src, "rb");
|
||||
if (in == NULL) return -1;
|
||||
int fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0777);
|
||||
if (fd < 0) { fclose(in); return -1; }
|
||||
FILE *out = fdopen(fd, "wb");
|
||||
if (out == NULL) { close(fd); fclose(in); (void)unlink(dst); return -1; }
|
||||
unsigned char buf[65536];
|
||||
int bad = 0;
|
||||
for (;;) {
|
||||
size_t n = fread(buf, 1, sizeof buf, in);
|
||||
if (n != 0 && fwrite(buf, 1, n, out) != n) bad = 1;
|
||||
if (bad || n < sizeof buf) {
|
||||
if (ferror(in)) bad = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fclose(in) != 0) bad = 1;
|
||||
if (fclose(out) != 0) bad = 1;
|
||||
if (bad) (void)unlink(dst);
|
||||
return bad ? -1 : 0;
|
||||
}
|
||||
|
||||
struct septxnentry {
|
||||
char *stage;
|
||||
char *dst;
|
||||
@@ -5117,9 +5148,11 @@ sep_free_product_staging(struct sepproduct *products, int nproducts)
|
||||
for (int i = 0; i < nproducts; i++) {
|
||||
free(products[i].stage_status);
|
||||
free(products[i].stage_iface);
|
||||
free(products[i].stage_publish);
|
||||
free(products[i].stage_out);
|
||||
products[i].stage_status = NULL;
|
||||
products[i].stage_iface = NULL;
|
||||
products[i].stage_publish = NULL;
|
||||
products[i].stage_out = NULL;
|
||||
}
|
||||
}
|
||||
@@ -5158,11 +5191,13 @@ sep_validate_product_path_pair(const struct sepproduct *a,
|
||||
const char *ap[] = {
|
||||
a->stage_status != NULL ? a->status : NULL,
|
||||
a->stage_out != NULL ? a->out : NULL,
|
||||
a->stage_status, a->stage_out, a->stage_iface };
|
||||
a->stage_publish != NULL ? a->publish : NULL,
|
||||
a->stage_status, a->stage_out, a->stage_publish, a->stage_iface };
|
||||
const char *bp[] = {
|
||||
b->stage_status != NULL ? b->status : NULL,
|
||||
b->stage_out != NULL ? b->out : NULL,
|
||||
b->stage_status, b->stage_out, b->stage_iface };
|
||||
b->stage_publish != NULL ? b->publish : NULL,
|
||||
b->stage_status, b->stage_out, b->stage_publish, b->stage_iface };
|
||||
for (size_t i = 0; i < nelem(ap); i++) {
|
||||
if (ap[i] == NULL) continue;
|
||||
for (size_t j = 0; j < nelem(bp); j++) {
|
||||
@@ -5221,6 +5256,10 @@ sep_validate_request_staging(struct sepgraph *g, const char *scratch, int warm,
|
||||
&& sep_prepare_product_stage(&products[i].stage_status,
|
||||
products[i].status) < 0)
|
||||
return -1;
|
||||
if (products[i].publish != NULL && !products[i].no_tests
|
||||
&& sep_prepare_product_stage(&products[i].stage_publish,
|
||||
products[i].publish) < 0)
|
||||
return -1;
|
||||
if (emit_asm) continue;
|
||||
int owns_output = root_package ? publish_package
|
||||
: is_test ? !products[i].no_tests
|
||||
@@ -5336,7 +5375,8 @@ sep_discard_request_staging(struct sepgraph *g, const char *scratch, int warm,
|
||||
}
|
||||
for (int i = 0; i < nproducts; i++) {
|
||||
const char *path[] = { products[i].stage_out,
|
||||
products[i].stage_iface, products[i].stage_status };
|
||||
products[i].stage_publish, products[i].stage_iface,
|
||||
products[i].stage_status };
|
||||
for (size_t j = 0; j < nelem(path); j++)
|
||||
if (path[j] != NULL
|
||||
&& unlink(path[j]) != 0 && errno != ENOENT)
|
||||
@@ -5564,6 +5604,7 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
products[i].ptest = -1;
|
||||
products[i].pxtest = -1;
|
||||
products[i].stage_out = NULL;
|
||||
products[i].stage_publish = NULL;
|
||||
products[i].stage_iface = NULL;
|
||||
products[i].stage_status = NULL;
|
||||
}
|
||||
@@ -5876,6 +5917,9 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
if (!g->pkg[root].failed && sep_root_is_command(&g->pkg[root])
|
||||
&& validate_command_output_path(products[i].out) < 0)
|
||||
return 1;
|
||||
if (products[i].publish != NULL
|
||||
&& validate_command_output_path(products[i].publish) < 0)
|
||||
return 1;
|
||||
if (products[i].status != NULL
|
||||
&& validate_command_output_path(products[i].status) < 0)
|
||||
return 1;
|
||||
@@ -5980,8 +6024,11 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
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",
|
||||
&& sep_mkdirs(create_output_dir, is_test ? 0777 : 0700,
|
||||
&created_output) != 0) {
|
||||
fprintf(stderr, is_test
|
||||
? "ww: cannot create test output directory %s\n"
|
||||
: "ww: cannot create build output directory %s\n",
|
||||
create_output_dir);
|
||||
free(order);
|
||||
return 1;
|
||||
@@ -6527,6 +6574,14 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
g->pkg[root].failed = 1;
|
||||
goto request_fail;
|
||||
}
|
||||
if (products[i].publish != NULL
|
||||
&& (products[i].stage_publish == NULL
|
||||
|| copy_executable_stage(products[i].stage_out,
|
||||
products[i].stage_publish) != 0)) {
|
||||
fprintf(stderr, "ww: cannot stage test binary %s\n",
|
||||
products[i].publish);
|
||||
goto request_fail;
|
||||
}
|
||||
if (sep_stage_product_status(&products[i]) != 0) {
|
||||
fprintf(stderr, "ww: cannot stage package-test product\n");
|
||||
goto request_fail;
|
||||
@@ -6594,6 +6649,10 @@ prepare_transaction:
|
||||
&& sep_txn_add(&tx, products[i].stage_out,
|
||||
products[i].out) < 0)
|
||||
goto request_fail;
|
||||
if (products[i].stage_publish != NULL
|
||||
&& sep_txn_add(&tx, products[i].stage_publish,
|
||||
products[i].publish) < 0)
|
||||
goto request_fail;
|
||||
if (products[i].stage_iface != NULL) {
|
||||
char outiface[SEP_ARTIFACT_MAX];
|
||||
int on = snprintf(outiface, sizeof outiface, "%s.wwi",
|
||||
@@ -6655,6 +6714,7 @@ build_one_sep(const char *src, int entry_is_dir, const char *root_identity,
|
||||
.identity = root_identity,
|
||||
.test_package = test_package,
|
||||
.status = NULL,
|
||||
.publish = NULL,
|
||||
.artifact = NULL,
|
||||
.variant = root_variant,
|
||||
.root = -1,
|
||||
@@ -7203,9 +7263,9 @@ do_test(int argc, char **argv)
|
||||
}
|
||||
package_create_output_dir = argv[++i];
|
||||
} else if (strcmp(argv[i], "--ww-package-test") == 0) {
|
||||
if (i + 8 >= argc) {
|
||||
if (i + 9 >= argc) {
|
||||
fprintf(stderr,
|
||||
"ww test: --ww-package-test needs kind, package, production, internal, external, directory, output, and status\n");
|
||||
"ww test: --ww-package-test needs kind, package, production, internal, external, directory, output, publication, and status\n");
|
||||
return 2;
|
||||
}
|
||||
const char *kind = argv[++i];
|
||||
@@ -7215,6 +7275,7 @@ do_test(int argc, char **argv)
|
||||
const char *external = argv[++i];
|
||||
const char *dir = argv[++i];
|
||||
const char *output = argv[++i];
|
||||
const char *publish = argv[++i];
|
||||
const char *status = argv[++i];
|
||||
size_t pn = strlen(name);
|
||||
int build_product = strcmp(kind, "build") == 0;
|
||||
@@ -7225,6 +7286,7 @@ do_test(int argc, char **argv)
|
||||
if ((!build_product && !test_product)
|
||||
|| pn == 0
|
||||
|| dir[0] == '\0' || output[0] == '\0'
|
||||
|| publish[0] == '\0'
|
||||
|| status[0] == '\0'
|
||||
|| (has_production && strcmp(production, name) != 0)
|
||||
|| (has_internal && strcmp(internal, name) != 0)
|
||||
@@ -7232,9 +7294,12 @@ do_test(int argc, char **argv)
|
||||
|| strncmp(external, name, pn) != 0
|
||||
|| strcmp(external + pn, "_test") != 0))
|
||||
|| (build_product && (!has_production
|
||||
|| has_internal || has_external))
|
||||
|| has_internal || has_external
|
||||
|| strcmp(publish, "-") != 0))
|
||||
|| (test_product && !has_production
|
||||
&& !has_internal && !has_external)) {
|
||||
&& !has_internal && !has_external)
|
||||
|| (test_product && !has_internal && !has_external
|
||||
&& strcmp(publish, "-") != 0)) {
|
||||
fprintf(stderr,
|
||||
"ww test: invalid --ww-package-test product\n");
|
||||
return 2;
|
||||
@@ -7256,6 +7321,8 @@ do_test(int argc, char **argv)
|
||||
products[nproducts].external_package = has_external
|
||||
? external : NULL;
|
||||
products[nproducts].status = status;
|
||||
products[nproducts].publish = strcmp(publish, "-") == 0
|
||||
? NULL : publish;
|
||||
products[nproducts].artifact = NULL;
|
||||
products[nproducts].variant = build_product
|
||||
? SEP_VARIANT_PRODUCTION : SEP_VARIANT_TEST_MAIN;
|
||||
@@ -7389,7 +7456,7 @@ do_test(int argc, char **argv)
|
||||
fprintf(stderr, "ww test: invalid --ww-package-publish\n");
|
||||
return 2;
|
||||
}
|
||||
if (package_create_output_dir != NULL && !package_build) {
|
||||
if (package_create_output_dir != NULL && nproducts == 0) {
|
||||
fprintf(stderr, "ww test: invalid private directory creation\n");
|
||||
return 2;
|
||||
}
|
||||
@@ -7460,13 +7527,8 @@ do_test(int argc, char **argv)
|
||||
"ww test: -S needs a single test file\n");
|
||||
return 2;
|
||||
}
|
||||
/* -c -o forwards: the coordinator names the single
|
||||
* package's artifact and rejects a multi-package fan-out. */
|
||||
if (outstem[0] && !compileonly) {
|
||||
fprintf(stderr,
|
||||
"ww test: -o needs -c for a package target\n");
|
||||
return 2;
|
||||
}
|
||||
/* The coordinator independently wires -o retention and -c run
|
||||
* suppression after it has loaded the complete package set. */
|
||||
/* -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);
|
||||
@@ -7488,11 +7550,6 @@ do_test(int argc, char **argv)
|
||||
"ww test: -S needs a single test file\n");
|
||||
return 2;
|
||||
}
|
||||
if (outstem[0] && !compileonly) {
|
||||
fprintf(stderr,
|
||||
"ww test: -o needs -c for a package target\n");
|
||||
return 2;
|
||||
}
|
||||
if (nproducts != 0) {
|
||||
if (!compileonly) {
|
||||
fprintf(stderr,
|
||||
@@ -7656,10 +7713,6 @@ do_test(int argc, char **argv)
|
||||
fprintf(stderr, "ww test: -S needs a single test file\n");
|
||||
return 2;
|
||||
}
|
||||
if (outstem[0] && !compileonly) {
|
||||
fprintf(stderr, "ww test: -o needs -c for a package target\n");
|
||||
return 2;
|
||||
}
|
||||
if (nproducts != 0) {
|
||||
if (!compileonly) {
|
||||
fprintf(stderr,
|
||||
|
||||
Reference in New Issue
Block a user