runner.c (41742B)
1 #include "runner.h" 2 3 #include "protocol.h" 4 5 #include <stdio.h> 6 #include <string.h> 7 8 static int path_join2(char* out, size_t cap, const char* a, const char* b) { 9 size_t na, nb; 10 int need_sep; 11 if (!out || cap == 0u || !a || !b) return BUILD_ERR; 12 na = strlen(a); 13 nb = strlen(b); 14 need_sep = na > 0u && a[na - 1u] != '/'; 15 if (na + (need_sep ? 1u : 0u) + nb + 1u > cap) return BUILD_ERR; 16 memcpy(out, a, na); 17 if (need_sep) out[na++] = '/'; 18 memcpy(out + na, b, nb); 19 out[na + nb] = '\0'; 20 return BUILD_OK; 21 } 22 23 static int target_copy(KitSlice target, char out[BUILD_TARGET_MAX]) { 24 if (!target.s || target.len == 0u || target.len >= BUILD_TARGET_MAX) 25 return BUILD_ERR; 26 memcpy(out, target.s, target.len); 27 out[target.len] = '\0'; 28 return BUILD_OK; 29 } 30 31 typedef struct BuildRunScratch { 32 BuildConfigLeaf configs[BUILD_RECIPE_CONFIG_CAP]; 33 BuildSourceLeaf sources[BUILD_RECIPE_SOURCE_CAP]; 34 BuildGlobLeaf globs[BUILD_RECIPE_GLOB_CAP]; 35 BuildBlobLeaf blobs[BUILD_RECIPE_BLOB_CAP]; 36 BuildDepEdge deps[BUILD_RECIPE_DEP_CAP]; 37 const BuildLeafSet* child_leafsets[BUILD_RECIPE_DEP_CAP]; 38 BuildPendingNeed pending[BUILD_RECIPE_DEP_CAP]; 39 } BuildRunScratch; 40 41 static BuildRunScratch* build_run_scratch_new(KitBuildCoordinator* c) { 42 BuildRunScratch* s; 43 if (!c || !c->ctx || !c->ctx->heap) return NULL; 44 s = (BuildRunScratch*)c->ctx->heap->alloc(c->ctx->heap, sizeof *s, 45 _Alignof(BuildRunScratch)); 46 if (s) memset(s, 0, sizeof *s); 47 return s; 48 } 49 50 static void build_run_scratch_free(KitBuildCoordinator* c, 51 BuildRunScratch* s) { 52 if (c && c->ctx && c->ctx->heap && s) 53 c->ctx->heap->free(c->ctx->heap, s, sizeof *s); 54 } 55 56 static void build_dep_log_init(BuildDepLog* log, BuildRunScratch* scratch) { 57 memset(log, 0, sizeof *log); 58 log->configs = scratch->configs; 59 log->cap_configs = sizeof scratch->configs / sizeof scratch->configs[0]; 60 log->sources = scratch->sources; 61 log->cap_sources = sizeof scratch->sources / sizeof scratch->sources[0]; 62 log->globs = scratch->globs; 63 log->cap_globs = sizeof scratch->globs / sizeof scratch->globs[0]; 64 log->blobs = scratch->blobs; 65 log->cap_blobs = sizeof scratch->blobs / sizeof scratch->blobs[0]; 66 log->deps = scratch->deps; 67 log->cap_deps = sizeof scratch->deps / sizeof scratch->deps[0]; 68 log->child_leafsets = scratch->child_leafsets; 69 log->cap_children = 70 sizeof scratch->child_leafsets / sizeof scratch->child_leafsets[0]; 71 log->pending = scratch->pending; 72 log->cap_pending = sizeof scratch->pending / sizeof scratch->pending[0]; 73 log->next_token = 1; 74 } 75 76 static void hash_slice(KitSlice s, uint8_t out[BUILD_HASH_LEN]) { 77 KitBlobInfo bi; 78 static const uint8_t empty = 0; 79 kit_blob_info(&bi, s.len ? s.data : &empty, s.len); 80 memcpy(out, bi.id, BUILD_HASH_LEN); 81 } 82 83 static int config_leaf_eq(const BuildConfigLeaf* a, const BuildConfigLeaf* b) { 84 return strcmp(a->key, b->key) == 0 && a->present == b->present && 85 a->has_default == b->has_default && 86 build_id_eq(a->value_hash, b->value_hash) && 87 build_id_eq(a->default_hash, b->default_hash); 88 } 89 90 static int append_config_observation(BuildDepLog* log, const BuildConfig* cfg, 91 KitSlice key, KitSlice default_value, 92 int has_default) { 93 BuildConfigLeaf leaf; 94 BuildConfigLeaf* row; 95 KitSlice actual; 96 size_t i; 97 if (!log || !key.s || key.len == 0u || key.len >= BUILD_KEY_MAX) 98 return BUILD_ERR; 99 if (has_default && 100 (default_value.len >= BUILD_VAL_MAX || 101 (default_value.len && !default_value.s))) 102 return BUILD_ERR; 103 memset(&leaf, 0, sizeof leaf); 104 memcpy(leaf.key, key.s, key.len); 105 leaf.key[key.len] = '\0'; 106 actual = KIT_SLICE_NULL; 107 if (build_config_get(cfg, key, &actual, &leaf.present) != BUILD_OK) 108 return BUILD_ERR; 109 leaf.has_default = has_default ? 1 : 0; 110 if (leaf.present) { 111 hash_slice(actual, leaf.value_hash); 112 } else if (leaf.has_default) { 113 hash_slice(default_value, leaf.value_hash); 114 } 115 if (leaf.has_default) hash_slice(default_value, leaf.default_hash); 116 for (i = 0; i < log->n_configs; ++i) { 117 if (config_leaf_eq(&log->configs[i], &leaf)) 118 return BUILD_OK; 119 } 120 if (log->n_configs >= log->cap_configs) return BUILD_ERR; 121 row = &log->configs[log->n_configs++]; 122 *row = leaf; 123 return BUILD_OK; 124 } 125 126 static int append_source(BuildDepLog* log, KitSlice path, 127 const uint8_t blob[BUILD_HASH_LEN], int present) { 128 BuildSourceLeaf* row; 129 size_t i; 130 if (!log || !path.s || path.len == 0u || path.len >= BUILD_PATH_MAX) 131 return BUILD_ERR; 132 for (i = 0; i < log->n_sources; ++i) { 133 row = &log->sources[i]; 134 if (strlen(row->path) == path.len && 135 memcmp(row->path, path.s, path.len) == 0) { 136 int absent = present ? 0 : 1; 137 if (row->absent != absent) return BUILD_ERR; 138 if (!row->absent && !build_id_eq(row->blob, blob)) return BUILD_ERR; 139 return BUILD_OK; 140 } 141 } 142 if (log->n_sources >= log->cap_sources) return BUILD_ERR; 143 row = &log->sources[log->n_sources++]; 144 memcpy(row->path, path.s, path.len); 145 row->path[path.len] = '\0'; 146 row->absent = present ? 0 : 1; 147 if (present) 148 memcpy(row->blob, blob, BUILD_HASH_LEN); 149 else 150 memset(row->blob, 0, BUILD_HASH_LEN); 151 return BUILD_OK; 152 } 153 154 static int append_glob(BuildDepLog* log, KitSlice pattern, 155 const uint8_t result_hash[BUILD_HASH_LEN]) { 156 BuildGlobLeaf* row; 157 size_t i; 158 if (!log || !pattern.s || pattern.len == 0u || 159 pattern.len >= BUILD_PATTERN_MAX || !result_hash) 160 return BUILD_ERR; 161 for (i = 0; i < log->n_globs; ++i) { 162 row = &log->globs[i]; 163 if (strlen(row->pattern) == pattern.len && 164 memcmp(row->pattern, pattern.s, pattern.len) == 0) { 165 if (!build_id_eq(row->result_hash, result_hash)) return BUILD_ERR; 166 return BUILD_OK; 167 } 168 } 169 if (log->n_globs >= log->cap_globs) return BUILD_ERR; 170 row = &log->globs[log->n_globs++]; 171 memcpy(row->pattern, pattern.s, pattern.len); 172 row->pattern[pattern.len] = '\0'; 173 memcpy(row->result_hash, result_hash, BUILD_HASH_LEN); 174 return BUILD_OK; 175 } 176 177 static int append_blob(BuildDepLog* log, 178 const uint8_t blob[BUILD_HASH_LEN]) { 179 BuildBlobLeaf* row; 180 size_t i; 181 if (!log || !blob) return BUILD_ERR; 182 for (i = 0; i < log->n_blobs; ++i) { 183 row = &log->blobs[i]; 184 if (build_id_eq(row->blob, blob)) return BUILD_OK; 185 } 186 if (log->n_blobs >= log->cap_blobs) return BUILD_ERR; 187 row = &log->blobs[log->n_blobs++]; 188 memcpy(row->blob, blob, BUILD_HASH_LEN); 189 return BUILD_OK; 190 } 191 192 static int append_dep(BuildDepLog* log, KitSlice target, 193 const uint8_t overlay_id[BUILD_HASH_LEN], 194 const uint8_t argv_id[BUILD_HASH_LEN], 195 const BuildResolved* r) { 196 BuildDepEdge* row; 197 size_t i; 198 if (!log || !target.s || target.len == 0u || target.len >= BUILD_TARGET_MAX || 199 !overlay_id || !argv_id || !r || !r->leafset) 200 return BUILD_ERR; 201 for (i = 0; i < log->n_deps; ++i) { 202 row = &log->deps[i]; 203 if (strlen(row->name) == target.len && 204 memcmp(row->name, target.s, target.len) == 0 && 205 build_id_eq(row->overlay_id, overlay_id) && 206 build_id_eq(row->argv_id, argv_id) && 207 build_id_eq(row->output_tree, r->output_tree)) 208 return BUILD_OK; 209 } 210 if (log->n_deps >= log->cap_deps || 211 log->n_children >= log->cap_children) 212 return BUILD_ERR; 213 row = &log->deps[log->n_deps++]; 214 memcpy(row->name, target.s, target.len); 215 row->name[target.len] = '\0'; 216 memcpy(row->overlay_id, overlay_id, BUILD_HASH_LEN); 217 memcpy(row->argv_id, argv_id, BUILD_HASH_LEN); 218 memcpy(row->output_tree, r->output_tree, BUILD_HASH_LEN); 219 log->child_leafsets[log->n_children++] = r->leafset; 220 return BUILD_OK; 221 } 222 223 static int write_resp(KitBuildCoordinator* c, KitBuildConn* conn, 224 const BuildReq* req, const BuildResp* resp); 225 226 typedef struct BuildGlobStream { 227 KitBuildCoordinator* c; 228 KitBuildConn* conn; 229 BuildReq req; 230 int failed; 231 } BuildGlobStream; 232 233 static int glob_stream_cb(void* user, const char* path, 234 const uint8_t blob[BUILD_HASH_LEN]) { 235 BuildGlobStream* s = (BuildGlobStream*)user; 236 BuildResp resp; 237 (void)blob; 238 if (!s || !path) return 1; 239 memset(&resp, 0, sizeof resp); 240 resp.status = BUILD_RESP_OK; 241 resp.text = kit_slice_cstr(path); 242 if (write_resp(s->c, s->conn, &s->req, &resp) != BUILD_OK) { 243 s->failed = 1; 244 return 1; 245 } 246 return 0; 247 } 248 249 static BuildPendingNeed* find_pending(BuildDepLog* log, uint64_t token) { 250 size_t i; 251 if (!log) return NULL; 252 for (i = 0; i < log->n_pending; ++i) 253 if (log->pending[i].token == token) return &log->pending[i]; 254 return NULL; 255 } 256 257 static int write_resp(KitBuildCoordinator* c, KitBuildConn* conn, 258 const BuildReq* req, const BuildResp* resp) { 259 uint8_t frame[BUILD_FRAME_MAX]; 260 size_t n = 0; 261 if (!c || !conn || !req || !resp) return BUILD_ERR; 262 if (build_proto_encode_resp(req, resp, frame, sizeof frame, &n) != BUILD_OK) 263 return BUILD_ERR; 264 return c->host.transport->write_frame(c->host.transport->user, conn, frame, 265 n) == 0 266 ? BUILD_OK 267 : BUILD_ERR; 268 } 269 270 static void resp_error(BuildResp* resp, KitStatus st, const char* msg) { 271 memset(resp, 0, sizeof *resp); 272 resp->status = BUILD_RESP_ERROR; 273 resp->error_status = (uint16_t)st; 274 resp->text = kit_slice_cstr(msg ? msg : "build request failed"); 275 } 276 277 static int store_config_blob(KitBuildCoordinator* c, const BuildConfig* cfg, 278 uint8_t out[BUILD_HASH_LEN]) { 279 KitWriter* w = NULL; 280 const uint8_t* bytes; 281 size_t len; 282 KitBlobInfo bi; 283 int ok = BUILD_ERR; 284 if (kit_writer_mem(c->ctx->heap, &w) != KIT_OK || !w) return BUILD_ERR; 285 if (build_config_emit(cfg, w) != BUILD_OK || kit_writer_status(w) != KIT_OK) 286 goto out_close; 287 bytes = kit_writer_mem_bytes(w, &len); 288 if (kit_cas_add_blob(c->cas, bytes, len, &bi) != KIT_OK) goto out_close; 289 memcpy(out, bi.id, BUILD_HASH_LEN); 290 ok = BUILD_OK; 291 out_close: 292 kit_writer_close(w); 293 return ok; 294 } 295 296 static int store_argv_blob(KitBuildCoordinator* c, const BuildArgv* argv, 297 uint8_t out[BUILD_HASH_LEN]) { 298 KitWriter* w = NULL; 299 const uint8_t* bytes; 300 size_t len; 301 KitBlobInfo bi; 302 int ok = BUILD_ERR; 303 if (kit_writer_mem(c->ctx->heap, &w) != KIT_OK || !w) return BUILD_ERR; 304 if (build_argv_emit(argv, w) != BUILD_OK || kit_writer_status(w) != KIT_OK) 305 goto out_close; 306 bytes = kit_writer_mem_bytes(w, &len); 307 if (kit_cas_add_blob(c->cas, bytes, len, &bi) != KIT_OK) goto out_close; 308 memcpy(out, bi.id, BUILD_HASH_LEN); 309 ok = BUILD_OK; 310 out_close: 311 kit_writer_close(w); 312 return ok; 313 } 314 315 static int service_recipe_connections(KitBuildCoordinator* c, 316 KitBuildListener* listener, 317 KitBuildProc** proc, KitSlice target, 318 const BuildConfig* cfg, 319 const BuildChainFrame* chain, 320 BuildDepLog* log, int* exit_code) { 321 int done = 0; 322 KitBuildConn* conn = NULL; 323 if (!c || !listener || !proc || !*proc || !cfg || !log || !exit_code) 324 return BUILD_ERR; 325 if (!c->host.transport->try_accept || !c->host.exec->poll) { 326 if (c->host.transport->accept(c->host.transport->user, listener, &conn) != 327 0 || 328 !conn) 329 return BUILD_ERR; 330 if (build_runner_service(c, conn, target, cfg, chain, log) != BUILD_OK) { 331 c->host.transport->close(c->host.transport->user, conn); 332 return BUILD_ERR; 333 } 334 c->host.transport->close(c->host.transport->user, conn); 335 if (c->host.exec->wait(c->host.exec->user, *proc, exit_code, NULL, NULL) != 336 0) 337 return BUILD_ERR; 338 *proc = NULL; 339 return BUILD_OK; 340 } 341 while (!done) { 342 int ready = 0; 343 conn = NULL; 344 if (c->host.exec->poll(c->host.exec->user, *proc, &done, exit_code) != 0) 345 return BUILD_ERR; 346 if (done) break; 347 if (c->host.transport->try_accept(c->host.transport->user, listener, &conn, 348 &ready) != 0) 349 return BUILD_ERR; 350 if (!ready) continue; 351 if (!conn) return BUILD_ERR; 352 if (build_runner_service(c, conn, target, cfg, chain, log) != BUILD_OK) { 353 c->host.transport->close(c->host.transport->user, conn); 354 return BUILD_ERR; 355 } 356 c->host.transport->close(c->host.transport->user, conn); 357 } 358 *proc = NULL; 359 return BUILD_OK; 360 } 361 362 static int write_file_bytes(KitBuildCoordinator* c, const char* path, 363 const uint8_t* data, size_t len) { 364 KitWriter* w = NULL; 365 KitStatus st; 366 if (!c || !path || (!data && len) || !c->host.cas_host || 367 !c->host.cas_host->file_io || !c->host.cas_host->file_io->open_writer) 368 return BUILD_ERR; 369 if (c->host.cas_host->file_io->open_writer(c->host.cas_host->file_io->user, 370 path, &w) != KIT_OK || 371 !w) 372 return BUILD_ERR; 373 st = len ? kit_writer_write(w, data, len) : KIT_OK; 374 if (st == KIT_OK) st = kit_writer_status(w); 375 kit_writer_close(w); 376 return st == KIT_OK ? BUILD_OK : BUILD_ERR; 377 } 378 379 static int copy_capture_into_output(KitBuildCoordinator* c, 380 const char* capture_path, 381 const char* out_dir, const char* name, 382 uint8_t blob[BUILD_HASH_LEN]) { 383 KitFileData fd; 384 KitBlobInfo bi; 385 char dest[BUILD_PATH_MAX]; 386 int ok = BUILD_ERR; 387 if (!c || !capture_path || !out_dir || !name || !blob) return BUILD_ERR; 388 if (path_join2(dest, sizeof dest, out_dir, name) != BUILD_OK) return BUILD_ERR; 389 fd.data = NULL; 390 fd.size = 0; 391 fd.token = NULL; 392 if (!c->host.cas_host || !c->host.cas_host->file_io || 393 !c->host.cas_host->file_io->read_all || 394 c->host.cas_host->file_io->read_all(c->host.cas_host->file_io->user, 395 capture_path, &fd) != KIT_OK) 396 return BUILD_ERR; 397 if (write_file_bytes(c, dest, fd.data, fd.size) != BUILD_OK || 398 kit_cas_add_blob(c->cas, fd.data, fd.size, &bi) != KIT_OK) 399 goto out; 400 memcpy(blob, bi.id, BUILD_HASH_LEN); 401 ok = BUILD_OK; 402 out: 403 if (c->host.cas_host->file_io->release) 404 c->host.cas_host->file_io->release(c->host.cas_host->file_io->user, &fd); 405 return ok; 406 } 407 408 static int build_run_recipe_impl(KitBuildCoordinator* c, KitSlice target, 409 const BuildConfig* cfg, const BuildArgv* argv, 410 const BuildChainFrame* chain, 411 BuildResolved* out, int record_traces) { 412 BuildRecipeResolution recipe; 413 KitBuildListener* listener = NULL; 414 KitBuildConn* conn = NULL; 415 KitBuildProc* proc = NULL; 416 char endpoint[BUILD_PATH_MAX]; 417 char sandbox[BUILD_PATH_MAX]; 418 char out_dir[BUILD_PATH_MAX]; 419 KitSlice proc_argv[129]; 420 KitBuildKV env[140]; 421 char env_keys[128][BUILD_KEY_MAX]; 422 size_t argc = 0, nenv = 0, i, base_nenv = 0; 423 int exit_code = 1; 424 int ok = BUILD_ERR; 425 BuildRunScratch* scratch = NULL; 426 BuildDepLog log; 427 428 if (!c || !cfg || !argv || !out || !c->host.exec || !c->host.transport) 429 return BUILD_ERR; 430 endpoint[0] = '\0'; 431 sandbox[0] = '\0'; 432 out_dir[0] = '\0'; 433 memset(&recipe, 0, sizeof recipe); 434 if (build_coord_resolve_recipe(c, target, &recipe) != BUILD_OK) 435 return BUILD_ERR; 436 if (c->host.transport->listen(c->host.transport->user, endpoint, 437 sizeof endpoint, &listener) != 0 || 438 !listener) 439 return BUILD_ERR; 440 if (build_store_sandbox_new(&c->store, sandbox, sizeof sandbox, out_dir, 441 sizeof out_dir) != BUILD_OK) 442 goto out_cleanup; 443 444 scratch = build_run_scratch_new(c); 445 if (!scratch) goto out_cleanup; 446 build_dep_log_init(&log, scratch); 447 448 proc_argv[argc++] = kit_slice_cstr(recipe.recipe_abspath); 449 for (i = 0; i < argv->n && argc < sizeof proc_argv / sizeof proc_argv[0]; 450 ++i) 451 proc_argv[argc++] = kit_slice_cstr(argv->args[i]); 452 if (i != argv->n) goto out_cleanup; 453 454 env[nenv].key = KIT_SLICE_LIT(KIT_BUILD_ENV_SOCK); 455 env[nenv++].value = kit_slice_cstr(endpoint); 456 env[nenv].key = KIT_SLICE_LIT(KIT_BUILD_ENV_OUT); 457 env[nenv++].value = kit_slice_cstr(out_dir); 458 env[nenv].key = KIT_SLICE_LIT(KIT_BUILD_ENV_TARGET); 459 env[nenv++].value = target; 460 env[nenv].key = KIT_SLICE_LIT(KIT_BUILD_ENV_REPO); 461 env[nenv++].value = kit_slice_cstr(recipe.repo); 462 env[nenv].key = KIT_SLICE_LIT(KIT_BUILD_ENV_PACKAGE); 463 env[nenv++].value = kit_slice_cstr(recipe.package); 464 env[nenv].key = KIT_SLICE_LIT(KIT_BUILD_ENV_LOCAL); 465 env[nenv++].value = kit_slice_cstr(recipe.local_name); 466 base_nenv = nenv; 467 for (i = 0; i < cfg->n && nenv < sizeof env / sizeof env[0] && 468 nenv - base_nenv < sizeof env_keys / sizeof env_keys[0]; 469 ++i) { 470 const char* key = cfg->entries[i].key; 471 size_t prefix_len = sizeof(KIT_BUILD_ENV_PREFIX) - 1u; 472 if (strncmp(key, KIT_BUILD_ENV_PREFIX, prefix_len) != 0) continue; 473 if (append_config_observation(&log, cfg, kit_slice_cstr(key), 474 KIT_SLICE_NULL, 0) != BUILD_OK) 475 goto out_cleanup; 476 snprintf(env_keys[nenv - base_nenv], 477 sizeof env_keys[nenv - base_nenv], "%s", 478 key + prefix_len); 479 env[nenv].key = kit_slice_cstr(env_keys[nenv - base_nenv]); 480 env[nenv].value = kit_slice_cstr(cfg->entries[i].value); 481 ++nenv; 482 } 483 484 { 485 KitExecOpts eo; 486 memset(&eo, 0, sizeof eo); 487 eo.argv = proc_argv; 488 eo.argc = argc; 489 eo.env = env; 490 eo.nenv = nenv; 491 eo.cwd = kit_slice_cstr(recipe.workspace_root); 492 if (c->host.exec->spawn(c->host.exec->user, &eo, &proc) != 0 || !proc) 493 goto out_cleanup; 494 } 495 build_coord_stat_bump(c, BUILD_STAT_RECIPE_RUN); 496 if (service_recipe_connections(c, listener, &proc, target, cfg, chain, &log, 497 &exit_code) != BUILD_OK) 498 goto out_kill; 499 if (exit_code != 0) goto out_cleanup; 500 if (build_store_ingest_output(&c->store, out_dir, out->output_tree, out->path, 501 sizeof out->path) != BUILD_OK) 502 goto out_cleanup; 503 if (record_traces) { 504 if (build_runner_record_traces(c, target, argv, &log, 505 out->output_tree, &out->leafset) != BUILD_OK) 506 goto out_cleanup; 507 } else { 508 out->leafset = NULL; 509 } 510 ok = BUILD_OK; 511 goto out_cleanup; 512 513 out_kill: 514 if (proc && c->host.exec->kill) c->host.exec->kill(c->host.exec->user, proc); 515 if (proc && c->host.exec->wait) 516 (void)c->host.exec->wait(c->host.exec->user, proc, &exit_code, NULL, NULL); 517 proc = NULL; 518 out_cleanup: 519 if (conn) c->host.transport->close(c->host.transport->user, conn); 520 if (listener) 521 c->host.transport->close_listener(c->host.transport->user, listener); 522 if (sandbox[0]) build_store_sandbox_done(&c->store, sandbox); 523 build_run_scratch_free(c, scratch); 524 return ok; 525 } 526 527 static int build_run_test_recipe_impl(KitBuildCoordinator* c, KitSlice target, 528 const BuildConfig* cfg, 529 const BuildArgv* argv, 530 const BuildChainFrame* chain, 531 BuildTestResolved* out, 532 int record_traces) { 533 BuildRecipeResolution recipe; 534 KitBuildListener* listener = NULL; 535 KitBuildConn* conn = NULL; 536 KitBuildProc* proc = NULL; 537 char endpoint[BUILD_PATH_MAX]; 538 char sandbox[BUILD_PATH_MAX]; 539 char out_dir[BUILD_PATH_MAX]; 540 char stdout_path[BUILD_PATH_MAX]; 541 char stderr_path[BUILD_PATH_MAX]; 542 KitSlice proc_argv[129]; 543 KitBuildKV env[140]; 544 char env_keys[128][BUILD_KEY_MAX]; 545 size_t argc = 0, nenv = 0, i, base_nenv = 0; 546 int exit_code = 1; 547 int ok = BUILD_ERR; 548 BuildRunScratch* scratch = NULL; 549 BuildDepLog log; 550 551 if (!c || !cfg || !argv || !out || !c->host.exec || !c->host.transport || 552 !c->host.exec->spawn) 553 return BUILD_ERR; 554 endpoint[0] = '\0'; 555 sandbox[0] = '\0'; 556 out_dir[0] = '\0'; 557 stdout_path[0] = '\0'; 558 stderr_path[0] = '\0'; 559 memset(&recipe, 0, sizeof recipe); 560 if (build_coord_resolve_recipe(c, target, &recipe) != BUILD_OK) 561 return BUILD_ERR; 562 if (c->host.transport->listen(c->host.transport->user, endpoint, 563 sizeof endpoint, &listener) != 0 || 564 !listener) 565 return BUILD_ERR; 566 if (build_store_sandbox_new(&c->store, sandbox, sizeof sandbox, out_dir, 567 sizeof out_dir) != BUILD_OK) 568 goto out_cleanup; 569 if (path_join2(stdout_path, sizeof stdout_path, sandbox, "stdout") != 570 BUILD_OK || 571 path_join2(stderr_path, sizeof stderr_path, sandbox, "stderr") != 572 BUILD_OK) 573 goto out_cleanup; 574 575 scratch = build_run_scratch_new(c); 576 if (!scratch) goto out_cleanup; 577 build_dep_log_init(&log, scratch); 578 579 proc_argv[argc++] = kit_slice_cstr(recipe.recipe_abspath); 580 for (i = 0; i < argv->n && argc < sizeof proc_argv / sizeof proc_argv[0]; 581 ++i) 582 proc_argv[argc++] = kit_slice_cstr(argv->args[i]); 583 if (i != argv->n) goto out_cleanup; 584 585 env[nenv].key = KIT_SLICE_LIT(KIT_BUILD_ENV_SOCK); 586 env[nenv++].value = kit_slice_cstr(endpoint); 587 env[nenv].key = KIT_SLICE_LIT(KIT_BUILD_ENV_OUT); 588 env[nenv++].value = kit_slice_cstr(out_dir); 589 env[nenv].key = KIT_SLICE_LIT(KIT_BUILD_ENV_TARGET); 590 env[nenv++].value = target; 591 env[nenv].key = KIT_SLICE_LIT(KIT_BUILD_ENV_REPO); 592 env[nenv++].value = kit_slice_cstr(recipe.repo); 593 env[nenv].key = KIT_SLICE_LIT(KIT_BUILD_ENV_PACKAGE); 594 env[nenv++].value = kit_slice_cstr(recipe.package); 595 env[nenv].key = KIT_SLICE_LIT(KIT_BUILD_ENV_LOCAL); 596 env[nenv++].value = kit_slice_cstr(recipe.local_name); 597 base_nenv = nenv; 598 for (i = 0; i < cfg->n && nenv < sizeof env / sizeof env[0] && 599 nenv - base_nenv < sizeof env_keys / sizeof env_keys[0]; 600 ++i) { 601 const char* key = cfg->entries[i].key; 602 size_t prefix_len = sizeof(KIT_BUILD_ENV_PREFIX) - 1u; 603 if (strncmp(key, KIT_BUILD_ENV_PREFIX, prefix_len) != 0) continue; 604 if (append_config_observation(&log, cfg, kit_slice_cstr(key), 605 KIT_SLICE_NULL, 0) != BUILD_OK) 606 goto out_cleanup; 607 snprintf(env_keys[nenv - base_nenv], 608 sizeof env_keys[nenv - base_nenv], "%s", 609 key + prefix_len); 610 env[nenv].key = kit_slice_cstr(env_keys[nenv - base_nenv]); 611 env[nenv].value = kit_slice_cstr(cfg->entries[i].value); 612 ++nenv; 613 } 614 615 { 616 KitExecOpts eo; 617 memset(&eo, 0, sizeof eo); 618 eo.argv = proc_argv; 619 eo.argc = argc; 620 eo.env = env; 621 eo.nenv = nenv; 622 eo.cwd = kit_slice_cstr(recipe.workspace_root); 623 eo.stdout_path = kit_slice_cstr(stdout_path); 624 eo.stderr_path = kit_slice_cstr(stderr_path); 625 if (c->host.exec->spawn(c->host.exec->user, &eo, &proc) != 0 || !proc) 626 goto out_cleanup; 627 } 628 build_coord_stat_bump(c, BUILD_STAT_TEST_RUN); 629 if (service_recipe_connections(c, listener, &proc, target, cfg, chain, &log, 630 &exit_code) != BUILD_OK) 631 goto out_kill; 632 if (copy_capture_into_output(c, stdout_path, out_dir, "stdout", 633 out->stdout_blob) != BUILD_OK || 634 copy_capture_into_output(c, stderr_path, out_dir, "stderr", 635 out->stderr_blob) != BUILD_OK) 636 goto out_cleanup; 637 if (build_store_ingest_output(&c->store, out_dir, out->result_tree, out->path, 638 sizeof out->path) != BUILD_OK) 639 goto out_cleanup; 640 out->exit_code = exit_code; 641 out->status = exit_code == 0 ? KIT_TEST_PASS : KIT_TEST_FAIL; 642 if (out->status == KIT_TEST_PASS && record_traces) { 643 if (build_runner_record_test_traces(c, target, argv, &log, 644 out->result_tree, &out->leafset) != 645 BUILD_OK) 646 goto out_cleanup; 647 } else { 648 out->leafset = NULL; 649 if (out->status == KIT_TEST_FAIL) 650 build_coord_stat_bump(c, BUILD_STAT_TEST_FAILURE); 651 } 652 ok = BUILD_OK; 653 goto out_cleanup; 654 655 out_kill: 656 if (proc && c->host.exec->kill) c->host.exec->kill(c->host.exec->user, proc); 657 if (proc && c->host.exec->wait) 658 (void)c->host.exec->wait(c->host.exec->user, proc, &exit_code, NULL, NULL); 659 proc = NULL; 660 out_cleanup: 661 if (conn) c->host.transport->close(c->host.transport->user, conn); 662 if (listener) 663 c->host.transport->close_listener(c->host.transport->user, listener); 664 if (sandbox[0]) build_store_sandbox_done(&c->store, sandbox); 665 build_run_scratch_free(c, scratch); 666 return ok; 667 } 668 669 int build_run_recipe(KitBuildCoordinator* c, KitSlice target, 670 const BuildConfig* cfg, const BuildArgv* argv, 671 const BuildChainFrame* chain, BuildResolved* out) { 672 return build_run_recipe_impl(c, target, cfg, argv, chain, out, 1); 673 } 674 675 int build_run_recipe_probe(KitBuildCoordinator* c, KitSlice target, 676 const BuildConfig* cfg, const BuildArgv* argv, 677 const BuildChainFrame* chain, BuildResolved* out) { 678 return build_run_recipe_impl(c, target, cfg, argv, chain, out, 0); 679 } 680 681 int build_run_test_recipe(KitBuildCoordinator* c, KitSlice target, 682 const BuildConfig* cfg, const BuildArgv* argv, 683 const BuildChainFrame* chain, BuildTestResolved* out, 684 int record_traces) { 685 return build_run_test_recipe_impl(c, target, cfg, argv, chain, out, 686 record_traces); 687 } 688 689 int build_runner_service(KitBuildCoordinator* c, KitBuildConn* conn, 690 KitSlice target, const BuildConfig* cfg, 691 const BuildChainFrame* chain, BuildDepLog* log) { 692 uint8_t frame[BUILD_FRAME_MAX]; 693 size_t n = 0; 694 char current_repo[BUILD_KEY_MAX]; 695 char current_package[BUILD_PATH_MAX]; 696 char current_local[BUILD_TARGET_MAX]; 697 if (!c || !conn || !cfg || !log) return BUILD_ERR; 698 if (build_target_split_repo(target, current_repo, current_package, 699 current_local) != BUILD_OK) 700 return BUILD_ERR; 701 for (;;) { 702 BuildReq req; 703 KitBuildKV overrides[64]; 704 KitSlice argv_slices[64]; 705 BuildResp resp; 706 memset(&req, 0, sizeof req); 707 if (c->host.transport->read_frame(c->host.transport->user, conn, frame, 708 sizeof frame, &n) != 0) 709 return BUILD_OK; 710 if (build_proto_decode_req(frame, n, &req, overrides, 711 sizeof overrides / sizeof overrides[0], 712 argv_slices, 713 sizeof argv_slices / sizeof argv_slices[0]) != 714 BUILD_OK) 715 return BUILD_ERR; 716 memset(&resp, 0, sizeof resp); 717 resp.status = BUILD_RESP_OK; 718 if (req.cmd == BUILD_CMD_CONFIG_GET) { 719 KitSlice value; 720 int present = 0; 721 if (build_config_get(cfg, req.arg, &value, &present) != BUILD_OK || 722 append_config_observation(log, cfg, req.arg, 723 req.argc ? req.argv[0] : KIT_SLICE_NULL, 724 req.argc ? 1 : 0) != BUILD_OK) { 725 resp_error(&resp, KIT_ERR, "config-get failed"); 726 } else if (!present && req.argc) { 727 resp.status = BUILD_RESP_DEFAULT; 728 resp.text = req.argv[0]; 729 } else if (!present) { 730 resp.status = BUILD_RESP_UNSET; 731 } else { 732 resp.text = value; 733 } 734 if (write_resp(c, conn, &req, &resp) != BUILD_OK) return BUILD_ERR; 735 } else if (req.cmd == BUILD_CMD_SOURCE) { 736 uint8_t blob[BUILD_HASH_LEN]; 737 int present = 0; 738 char full[BUILD_PATH_MAX]; 739 BuildRecipeResolution recipe; 740 memset(&recipe, 0, sizeof recipe); 741 if (build_coord_source_hash_target(c, target, req.arg, blob, &present) != 742 BUILD_OK || 743 append_source(log, req.arg, blob, present) != BUILD_OK) { 744 resp_error(&resp, KIT_ERR, "source failed"); 745 } else if (!present) { 746 resp.status = BUILD_RESP_ABSENT; 747 } else if (build_coord_resolve_recipe(c, target, &recipe) != BUILD_OK || 748 path_join2(full, sizeof full, recipe.workspace_root, 749 req.arg.s) != BUILD_OK) { 750 resp_error(&resp, KIT_ERR, "source path failed"); 751 } else { 752 memcpy(resp.id, blob, BUILD_HASH_LEN); 753 resp.text = kit_slice_cstr(full); 754 } 755 if (write_resp(c, conn, &req, &resp) != BUILD_OK) return BUILD_ERR; 756 } else if (req.cmd == BUILD_CMD_FETCH) { 757 uint8_t blob[BUILD_HASH_LEN]; 758 char path[BUILD_PATH_MAX]; 759 if (kit_hex_decode(blob, req.arg.s, BUILD_HASH_LEN) != KIT_OK || 760 build_coord_fetch_blob(c, blob, req.argv, req.argc, path, 761 sizeof path) != BUILD_OK || 762 append_blob(log, blob) != BUILD_OK) { 763 resp_error(&resp, KIT_ERR, "fetch failed"); 764 } else { 765 memcpy(resp.id, blob, BUILD_HASH_LEN); 766 resp.text = kit_slice_cstr(path); 767 } 768 if (write_resp(c, conn, &req, &resp) != BUILD_OK) return BUILD_ERR; 769 } else if (req.cmd == BUILD_CMD_GLOB) { 770 BuildGlobStream stream; 771 uint8_t result_hash[BUILD_HASH_LEN]; 772 memset(&stream, 0, sizeof stream); 773 stream.c = c; 774 stream.conn = conn; 775 stream.req = req; 776 if (build_coord_glob_target(c, target, req.arg, result_hash, 777 glob_stream_cb, &stream) != BUILD_OK || 778 stream.failed || 779 append_glob(log, req.arg, result_hash) != BUILD_OK) { 780 resp_error(&resp, KIT_ERR, "glob failed"); 781 if (write_resp(c, conn, &req, &resp) != BUILD_OK) return BUILD_ERR; 782 } else { 783 resp.status = BUILD_RESP_GLOB_END; 784 if (write_resp(c, conn, &req, &resp) != BUILD_OK) return BUILD_ERR; 785 } 786 } else if (req.cmd == BUILD_CMD_NEED) { 787 BuildConfigEntry cfg_entries[128], overlay_entries[64]; 788 char argv_entries[64][BUILD_VAL_MAX]; 789 BuildConfig dep_cfg, overlay_cfg, empty_cfg; 790 BuildArgv dep_argv; 791 BuildResolved r; 792 uint8_t overlay_id[BUILD_HASH_LEN], argv_id[BUILD_HASH_LEN]; 793 char dep_target[BUILD_TARGET_MAX]; 794 build_config_init(&dep_cfg, cfg_entries, 795 sizeof cfg_entries / sizeof cfg_entries[0]); 796 build_config_init(&overlay_cfg, overlay_entries, 797 sizeof overlay_entries / sizeof overlay_entries[0]); 798 build_config_init(&empty_cfg, NULL, 0); 799 build_argv_init(&dep_argv, argv_entries, 800 sizeof argv_entries / sizeof argv_entries[0]); 801 if (build_coord_canonical_target(c, req.arg, kit_slice_cstr(current_repo), 802 kit_slice_cstr(current_package), 803 dep_target) != BUILD_OK || 804 build_config_overlay(cfg, req.overrides, req.noverrides, &dep_cfg) != 805 BUILD_OK || 806 build_config_overlay(&empty_cfg, req.overrides, req.noverrides, 807 &overlay_cfg) != BUILD_OK || 808 store_config_blob(c, &overlay_cfg, overlay_id) != BUILD_OK || 809 build_argv_set(&dep_argv, req.argv, req.argc) != BUILD_OK || 810 build_argv_id(c->ctx->heap, &dep_argv, argv_id) != BUILD_OK || 811 build_resolve(c, kit_slice_cstr(dep_target), &dep_cfg, &dep_argv, 812 chain, &r) != 813 BUILD_OK || 814 append_dep(log, kit_slice_cstr(dep_target), overlay_id, argv_id, 815 &r) != 816 BUILD_OK) { 817 resp_error(&resp, KIT_ERR, "need failed"); 818 } else { 819 memcpy(resp.id, r.output_tree, BUILD_HASH_LEN); 820 resp.text = kit_slice_cstr(r.path); 821 } 822 if (write_resp(c, conn, &req, &resp) != BUILD_OK) return BUILD_ERR; 823 } else if (req.cmd == BUILD_CMD_NEED_SUBMIT) { 824 BuildConfigEntry cfg_entries[128], overlay_entries[64]; 825 char argv_entries[64][BUILD_VAL_MAX]; 826 BuildConfig dep_cfg, overlay_cfg, empty_cfg; 827 BuildArgv dep_argv; 828 BuildTargetFuture* f = NULL; 829 BuildPendingNeed* p; 830 uint8_t overlay_id[BUILD_HASH_LEN], argv_id[BUILD_HASH_LEN]; 831 char dep_target[BUILD_TARGET_MAX]; 832 char err[128]; 833 build_config_init(&dep_cfg, cfg_entries, 834 sizeof cfg_entries / sizeof cfg_entries[0]); 835 build_config_init(&overlay_cfg, overlay_entries, 836 sizeof overlay_entries / sizeof overlay_entries[0]); 837 build_config_init(&empty_cfg, NULL, 0); 838 build_argv_init(&dep_argv, argv_entries, 839 sizeof argv_entries / sizeof argv_entries[0]); 840 if (log->n_pending >= log->cap_pending || 841 build_coord_canonical_target(c, req.arg, kit_slice_cstr(current_repo), 842 kit_slice_cstr(current_package), 843 dep_target) != BUILD_OK || 844 build_config_overlay(cfg, req.overrides, req.noverrides, &dep_cfg) != 845 BUILD_OK || 846 build_config_overlay(&empty_cfg, req.overrides, req.noverrides, 847 &overlay_cfg) != BUILD_OK || 848 store_config_blob(c, &overlay_cfg, overlay_id) != BUILD_OK || 849 build_argv_set(&dep_argv, req.argv, req.argc) != BUILD_OK || 850 build_argv_id(c->ctx->heap, &dep_argv, argv_id) != BUILD_OK || 851 build_dispatch(c, kit_slice_cstr(dep_target), &dep_cfg, &dep_argv, 852 chain, &f, err, sizeof err) != BUILD_OK) { 853 resp_error(&resp, KIT_ERR, "need-submit failed"); 854 } else { 855 p = &log->pending[log->n_pending++]; 856 memset(p, 0, sizeof *p); 857 p->token = log->next_token++; 858 target_copy(kit_slice_cstr(dep_target), p->dep); 859 memcpy(p->overlay_id, overlay_id, BUILD_HASH_LEN); 860 memcpy(p->argv_id, argv_id, BUILD_HASH_LEN); 861 p->future = f; 862 resp.token = p->token; 863 } 864 if (write_resp(c, conn, &req, &resp) != BUILD_OK) return BUILD_ERR; 865 } else if (req.cmd == BUILD_CMD_NEED_AWAIT) { 866 BuildPendingNeed* p = find_pending(log, req.token); 867 BuildResolved r; 868 if (!p) { 869 resp_error(&resp, KIT_ERR, "need-await failed"); 870 } else if (p->awaited) { 871 memcpy(resp.id, p->result.output_tree, BUILD_HASH_LEN); 872 resp.text = kit_slice_cstr(p->result.path); 873 } else if (build_coord_target_await(c, p->future, &r) != BUILD_OK || 874 append_dep(log, kit_slice_cstr(p->dep), p->overlay_id, 875 p->argv_id, &r) != BUILD_OK) { 876 resp_error(&resp, KIT_ERR, "need-await failed"); 877 } else { 878 p->awaited = 1; 879 p->result = r; 880 memcpy(resp.id, r.output_tree, BUILD_HASH_LEN); 881 resp.text = kit_slice_cstr(r.path); 882 } 883 if (write_resp(c, conn, &req, &resp) != BUILD_OK) return BUILD_ERR; 884 } else { 885 return BUILD_ERR; 886 } 887 } 888 } 889 890 int build_runner_record_traces(KitBuildCoordinator* c, KitSlice target, 891 const BuildArgv* argv, const BuildDepLog* log, 892 const uint8_t output[BUILD_HASH_LEN], 893 const BuildLeafSet** out_leafset) { 894 BuildLeafSet direct; 895 BuildShallowTrace shallow; 896 BuildDeepTrace deep; 897 KitWriter* w = NULL; 898 const uint8_t* bytes; 899 size_t len; 900 uint8_t trace_id[BUILD_HASH_LEN]; 901 uint8_t target_key[BUILD_HASH_LEN]; 902 char err[128]; 903 int ok = BUILD_ERR; 904 905 if (!c || !argv || !log || !output || !out_leafset) 906 return BUILD_ERR; 907 memset(&direct, 0, sizeof direct); 908 if (target_copy(target, direct.target) != BUILD_OK) return BUILD_ERR; 909 if (build_coord_recipe_id(c, target, direct.recipe) != BUILD_OK) 910 return BUILD_ERR; 911 direct.configs = log->configs; 912 direct.n_configs = log->n_configs; 913 direct.sources = log->sources; 914 direct.n_sources = log->n_sources; 915 direct.globs = log->globs; 916 direct.n_globs = log->n_globs; 917 direct.blobs = log->blobs; 918 direct.n_blobs = log->n_blobs; 919 direct.children = log->child_leafsets; 920 direct.n_children = log->n_children; 921 if (build_leafset_union(c, &direct, log->deps, log->child_leafsets, 922 log->n_children, out_leafset) != BUILD_OK) 923 return BUILD_ERR; 924 925 memset(&shallow, 0, sizeof shallow); 926 if (target_copy(target, shallow.target) != BUILD_OK) return BUILD_ERR; 927 memcpy(shallow.recipe, direct.recipe, BUILD_HASH_LEN); 928 memcpy(shallow.output, output, BUILD_HASH_LEN); 929 if (store_argv_blob(c, argv, shallow.argv) != BUILD_OK) 930 return BUILD_ERR; 931 shallow.configs = log->configs; 932 shallow.n_configs = log->n_configs; 933 shallow.sources = log->sources; 934 shallow.n_sources = log->n_sources; 935 shallow.globs = log->globs; 936 shallow.n_globs = log->n_globs; 937 shallow.blobs = log->blobs; 938 shallow.n_blobs = log->n_blobs; 939 shallow.deps = log->deps; 940 shallow.n_deps = log->n_deps; 941 942 if (kit_writer_mem(c->ctx->heap, &w) != KIT_OK || !w) return BUILD_ERR; 943 if (build_shallow_emit(&shallow, w, err, sizeof err) != BUILD_OK || 944 kit_writer_status(w) != KIT_OK) 945 goto out; 946 bytes = kit_writer_mem_bytes(w, &len); 947 if (build_store_put_trace(&c->store, bytes, len, trace_id) != BUILD_OK) 948 goto out; 949 if (build_target_key(target, target_key) != BUILD_OK || 950 build_store_record_update(&c->store, target_key, target, 951 BUILD_TRACE_SHALLOW, trace_id) != BUILD_OK) 952 goto out; 953 kit_writer_close(w); 954 w = NULL; 955 956 memset(&deep, 0, sizeof deep); 957 if (target_copy(target, deep.target) != BUILD_OK) return BUILD_ERR; 958 memcpy(deep.recipe, direct.recipe, BUILD_HASH_LEN); 959 memcpy(deep.output, output, BUILD_HASH_LEN); 960 memcpy(deep.argv, shallow.argv, BUILD_HASH_LEN); 961 memcpy(deep.deepset, (*out_leafset)->id, BUILD_HASH_LEN); 962 if (kit_writer_mem(c->ctx->heap, &w) != KIT_OK || !w) return BUILD_ERR; 963 if (build_deep_emit(&deep, w, err, sizeof err) != BUILD_OK || 964 kit_writer_status(w) != KIT_OK) 965 goto out; 966 bytes = kit_writer_mem_bytes(w, &len); 967 if (build_store_put_trace(&c->store, bytes, len, trace_id) != BUILD_OK) 968 goto out; 969 if (build_store_record_update(&c->store, target_key, target, BUILD_TRACE_DEEP, 970 trace_id) != BUILD_OK) 971 goto out; 972 ok = BUILD_OK; 973 out: 974 if (w) kit_writer_close(w); 975 return ok; 976 } 977 978 int build_runner_record_test_traces(KitBuildCoordinator* c, KitSlice target, 979 const BuildArgv* argv, 980 const BuildDepLog* log, 981 const uint8_t result[BUILD_HASH_LEN], 982 const BuildLeafSet** out_leafset) { 983 BuildLeafSet direct; 984 BuildShallowTrace shallow; 985 BuildDeepTrace deep; 986 KitWriter* w = NULL; 987 const uint8_t* bytes; 988 size_t len; 989 uint8_t trace_id[BUILD_HASH_LEN]; 990 uint8_t target_key[BUILD_HASH_LEN]; 991 char err[128]; 992 int ok = BUILD_ERR; 993 994 if (!c || !argv || !log || !result || !out_leafset) 995 return BUILD_ERR; 996 memset(&direct, 0, sizeof direct); 997 if (target_copy(target, direct.target) != BUILD_OK) return BUILD_ERR; 998 if (build_coord_recipe_id(c, target, direct.recipe) != BUILD_OK) 999 return BUILD_ERR; 1000 direct.configs = log->configs; 1001 direct.n_configs = log->n_configs; 1002 direct.sources = log->sources; 1003 direct.n_sources = log->n_sources; 1004 direct.globs = log->globs; 1005 direct.n_globs = log->n_globs; 1006 direct.blobs = log->blobs; 1007 direct.n_blobs = log->n_blobs; 1008 direct.children = log->child_leafsets; 1009 direct.n_children = log->n_children; 1010 if (build_leafset_union(c, &direct, log->deps, log->child_leafsets, 1011 log->n_children, out_leafset) != BUILD_OK) 1012 return BUILD_ERR; 1013 1014 memset(&shallow, 0, sizeof shallow); 1015 if (target_copy(target, shallow.target) != BUILD_OK) return BUILD_ERR; 1016 memcpy(shallow.recipe, direct.recipe, BUILD_HASH_LEN); 1017 memcpy(shallow.output, result, BUILD_HASH_LEN); 1018 if (store_argv_blob(c, argv, shallow.argv) != BUILD_OK) 1019 return BUILD_ERR; 1020 shallow.configs = log->configs; 1021 shallow.n_configs = log->n_configs; 1022 shallow.sources = log->sources; 1023 shallow.n_sources = log->n_sources; 1024 shallow.globs = log->globs; 1025 shallow.n_globs = log->n_globs; 1026 shallow.blobs = log->blobs; 1027 shallow.n_blobs = log->n_blobs; 1028 shallow.deps = log->deps; 1029 shallow.n_deps = log->n_deps; 1030 1031 if (kit_writer_mem(c->ctx->heap, &w) != KIT_OK || !w) return BUILD_ERR; 1032 if (build_test_shallow_emit(&shallow, w, err, sizeof err) != BUILD_OK || 1033 kit_writer_status(w) != KIT_OK) 1034 goto out; 1035 bytes = kit_writer_mem_bytes(w, &len); 1036 if (build_store_put_trace(&c->store, bytes, len, trace_id) != BUILD_OK) 1037 goto out; 1038 if (build_test_target_key(target, target_key) != BUILD_OK || 1039 build_store_record_update(&c->store, target_key, target, 1040 BUILD_TRACE_SHALLOW, trace_id) != BUILD_OK) 1041 goto out; 1042 kit_writer_close(w); 1043 w = NULL; 1044 1045 memset(&deep, 0, sizeof deep); 1046 if (target_copy(target, deep.target) != BUILD_OK) return BUILD_ERR; 1047 memcpy(deep.recipe, direct.recipe, BUILD_HASH_LEN); 1048 memcpy(deep.output, result, BUILD_HASH_LEN); 1049 memcpy(deep.argv, shallow.argv, BUILD_HASH_LEN); 1050 memcpy(deep.deepset, (*out_leafset)->id, BUILD_HASH_LEN); 1051 if (kit_writer_mem(c->ctx->heap, &w) != KIT_OK || !w) return BUILD_ERR; 1052 if (build_test_deep_emit(&deep, w, err, sizeof err) != BUILD_OK || 1053 kit_writer_status(w) != KIT_OK) 1054 goto out; 1055 bytes = kit_writer_mem_bytes(w, &len); 1056 if (build_store_put_trace(&c->store, bytes, len, trace_id) != BUILD_OK) 1057 goto out; 1058 if (build_store_record_update(&c->store, target_key, target, BUILD_TRACE_DEEP, 1059 trace_id) != BUILD_OK) 1060 goto out; 1061 ok = BUILD_OK; 1062 out: 1063 if (w) kit_writer_close(w); 1064 return ok; 1065 }