resolve.c (46534B)
1 #include "resolve.h" 2 3 #include "remote.h" 4 #include "runner.h" 5 6 #undef KIT_TRACE_MODULE 7 #define KIT_TRACE_MODULE "build/resolve" 8 9 #include <stdio.h> 10 #include <string.h> 11 12 static int path_join2(char* out, size_t cap, const char* a, const char* b) { 13 size_t na, nb; 14 int need_sep; 15 if (!out || cap == 0u || !a || !b) return BUILD_ERR; 16 na = strlen(a); 17 nb = strlen(b); 18 need_sep = na > 0u && a[na - 1u] != '/'; 19 if (na + (need_sep ? 1u : 0u) + nb + 1u > cap) return BUILD_ERR; 20 memcpy(out, a, na); 21 if (need_sep) out[na++] = '/'; 22 memcpy(out + na, b, nb); 23 out[na + nb] = '\0'; 24 return BUILD_OK; 25 } 26 27 static int target_copy(KitSlice target, char out[BUILD_TARGET_MAX]) { 28 if (!target.s || target.len == 0u || target.len >= BUILD_TARGET_MAX) 29 return BUILD_ERR; 30 memcpy(out, target.s, target.len); 31 out[target.len] = '\0'; 32 return BUILD_OK; 33 } 34 35 static size_t count_lines(const uint8_t* data, size_t len) { 36 size_t i, n = 0; 37 for (i = 0; i < len; ++i) 38 if (data[i] == '\n') ++n; 39 return n; 40 } 41 42 static void hash_slice(KitSlice s, uint8_t out[BUILD_HASH_LEN]) { 43 KitBlobInfo bi; 44 static const uint8_t empty = 0; 45 kit_blob_info(&bi, s.len ? s.data : &empty, s.len); 46 memcpy(out, bi.id, BUILD_HASH_LEN); 47 } 48 49 static int config_observation_match(const BuildConfig* cfg, 50 const BuildConfigLeaf* obs) { 51 KitSlice value; 52 uint8_t value_hash[BUILD_HASH_LEN]; 53 int present = 0; 54 if (!cfg || !obs) return 0; 55 if (build_config_get(cfg, kit_slice_cstr(obs->key), &value, &present) != 56 BUILD_OK) 57 return 0; 58 if (present != obs->present) return 0; 59 if (!present) return 1; 60 hash_slice(value, value_hash); 61 return build_id_eq(value_hash, obs->value_hash); 62 } 63 64 static int config_leaf_eq(const BuildConfigLeaf* a, const BuildConfigLeaf* b) { 65 return a && b && strcmp(a->key, b->key) == 0 && a->present == b->present && 66 a->has_default == b->has_default && 67 build_id_eq(a->value_hash, b->value_hash) && 68 build_id_eq(a->default_hash, b->default_hash); 69 } 70 71 static int config_map_has_key(const BuildConfig* cfg, const char* key) { 72 KitSlice value; 73 int present = 0; 74 if (!cfg || !key) return 0; 75 if (build_config_get(cfg, kit_slice_cstr(key), &value, &present) != BUILD_OK) 76 return 0; 77 return present; 78 } 79 80 static int projected_config_append(KitBuildCoordinator* c, 81 BuildConfigLeaf** rows, size_t* n, 82 size_t* cap, 83 const BuildConfigLeaf* row) { 84 size_t i, newcap, old_size, new_size; 85 BuildConfigLeaf* fresh; 86 if (!c || !rows || !n || !cap || !row) return BUILD_ERR; 87 for (i = 0; i < *n; ++i) { 88 if (config_leaf_eq(&(*rows)[i], row)) return BUILD_OK; 89 } 90 if (*n == *cap) { 91 newcap = *cap ? *cap * 2u : 16u; 92 if (newcap < *cap || newcap > ((size_t)-1) / sizeof **rows) 93 return BUILD_ERR; 94 old_size = *cap * sizeof **rows; 95 new_size = newcap * sizeof **rows; 96 fresh = (BuildConfigLeaf*)c->ctx->heap->realloc( 97 c->ctx->heap, *rows, old_size, new_size, _Alignof(BuildConfigLeaf)); 98 if (!fresh) return BUILD_ERR; 99 *rows = fresh; 100 *cap = newcap; 101 } 102 (*rows)[(*n)++] = *row; 103 return BUILD_OK; 104 } 105 106 static int projected_config_collect(KitBuildCoordinator* c, 107 const BuildLeafSet* direct, 108 const BuildDepEdge* deps, 109 const BuildLeafSet* const* children, 110 size_t nchildren, 111 BuildConfigLeaf** out_rows, 112 size_t* out_n, size_t* out_cap) { 113 size_t i, j; 114 if (!c || !direct || !out_rows || !out_n || !out_cap) return BUILD_ERR; 115 *out_rows = NULL; 116 *out_n = 0; 117 *out_cap = 0; 118 for (i = 0; i < direct->n_configs; ++i) { 119 if (projected_config_append(c, out_rows, out_n, out_cap, 120 &direct->configs[i]) != BUILD_OK) 121 return BUILD_ERR; 122 } 123 for (i = 0; i < nchildren; ++i) { 124 BuildConfigEntry overlay_entries[64]; 125 BuildConfig overlay_cfg; 126 if (!deps || !children || !children[i]) return BUILD_ERR; 127 build_config_init(&overlay_cfg, overlay_entries, 128 sizeof overlay_entries / sizeof overlay_entries[0]); 129 if (build_coord_config_by_id(c, deps[i].overlay_id, &overlay_cfg) != 130 BUILD_OK) 131 return BUILD_ERR; 132 for (j = 0; j < children[i]->n_configs; ++j) { 133 if (config_map_has_key(&overlay_cfg, children[i]->configs[j].key)) 134 continue; 135 if (projected_config_append(c, out_rows, out_n, out_cap, 136 &children[i]->configs[j]) != BUILD_OK) 137 return BUILD_ERR; 138 } 139 } 140 return BUILD_OK; 141 } 142 143 typedef struct BuildSeenId { 144 uint8_t id[BUILD_HASH_LEN]; 145 } BuildSeenId; 146 147 typedef struct BuildLeafsetCheck { 148 KitHeap* heap; 149 BuildSourceLeaf* sources; 150 size_t n_sources; 151 size_t cap_sources; 152 BuildGlobLeaf* globs; 153 size_t n_globs; 154 size_t cap_globs; 155 BuildSeenId* visited; 156 size_t n_visited; 157 size_t cap_visited; 158 char* err; 159 size_t errcap; 160 } BuildLeafsetCheck; 161 162 static int leafset_check_err(BuildLeafsetCheck* ck, const char* what, 163 const char* key) { 164 if (ck && ck->err && ck->errcap) { 165 if (key) 166 snprintf(ck->err, ck->errcap, "%s: %s", what, key); 167 else 168 snprintf(ck->err, ck->errcap, "%s", what); 169 } 170 return BUILD_ERR; 171 } 172 173 static int leafset_check_grow(BuildLeafsetCheck* ck, void** ptr, size_t* cap, 174 size_t want, size_t elem_size, 175 size_t elem_align) { 176 size_t newcap, old_size, new_size; 177 void* fresh; 178 if (!ck || !ck->heap || !ptr || !cap || elem_size == 0u) return BUILD_ERR; 179 if (*cap >= want) return BUILD_OK; 180 newcap = *cap ? *cap : 16u; 181 while (newcap < want) { 182 if (newcap > ((size_t)-1) / 2u) 183 return leafset_check_err(ck, "deepset consistency table too large", NULL); 184 newcap *= 2u; 185 } 186 if (newcap > ((size_t)-1) / elem_size) 187 return leafset_check_err(ck, "deepset consistency table too large", NULL); 188 old_size = *cap * elem_size; 189 new_size = newcap * elem_size; 190 fresh = ck->heap->realloc(ck->heap, *ptr, old_size, new_size, elem_align); 191 if (!fresh) return leafset_check_err(ck, "out of memory", NULL); 192 *ptr = fresh; 193 *cap = newcap; 194 return BUILD_OK; 195 } 196 197 static int leafset_check_source(BuildLeafsetCheck* ck, 198 const BuildSourceLeaf* row) { 199 size_t i; 200 if (!ck || !row) return BUILD_ERR; 201 for (i = 0; i < ck->n_sources; ++i) { 202 BuildSourceLeaf* seen = &ck->sources[i]; 203 if (strcmp(seen->path, row->path) != 0) continue; 204 if (seen->absent != row->absent) 205 return leafset_check_err(ck, "inconsistent source observation", 206 row->path); 207 if (!row->absent && !build_id_eq(seen->blob, row->blob)) 208 return leafset_check_err(ck, "inconsistent source observation", 209 row->path); 210 return BUILD_OK; 211 } 212 if (leafset_check_grow(ck, (void**)&ck->sources, &ck->cap_sources, 213 ck->n_sources + 1u, sizeof ck->sources[0], 214 _Alignof(BuildSourceLeaf)) != BUILD_OK) 215 return BUILD_ERR; 216 ck->sources[ck->n_sources++] = *row; 217 return BUILD_OK; 218 } 219 220 static int leafset_check_glob(BuildLeafsetCheck* ck, const BuildGlobLeaf* row) { 221 size_t i; 222 if (!ck || !row) return BUILD_ERR; 223 for (i = 0; i < ck->n_globs; ++i) { 224 BuildGlobLeaf* seen = &ck->globs[i]; 225 if (strcmp(seen->pattern, row->pattern) != 0) continue; 226 if (!build_id_eq(seen->result_hash, row->result_hash)) 227 return leafset_check_err(ck, "inconsistent glob observation", 228 row->pattern); 229 return BUILD_OK; 230 } 231 if (leafset_check_grow(ck, (void**)&ck->globs, &ck->cap_globs, 232 ck->n_globs + 1u, sizeof ck->globs[0], 233 _Alignof(BuildGlobLeaf)) != BUILD_OK) 234 return BUILD_ERR; 235 ck->globs[ck->n_globs++] = *row; 236 return BUILD_OK; 237 } 238 239 static int leafset_check_mark_visited(BuildLeafsetCheck* ck, 240 const uint8_t id[BUILD_HASH_LEN], 241 int* already_seen) { 242 size_t i; 243 if (!ck || !id || !already_seen) return BUILD_ERR; 244 *already_seen = 0; 245 for (i = 0; i < ck->n_visited; ++i) { 246 if (build_id_eq(ck->visited[i].id, id)) { 247 *already_seen = 1; 248 return BUILD_OK; 249 } 250 } 251 if (leafset_check_grow(ck, (void**)&ck->visited, &ck->cap_visited, 252 ck->n_visited + 1u, sizeof ck->visited[0], 253 _Alignof(BuildSeenId)) != BUILD_OK) 254 return BUILD_ERR; 255 memcpy(ck->visited[ck->n_visited++].id, id, BUILD_HASH_LEN); 256 return BUILD_OK; 257 } 258 259 static int leafset_check_walk(BuildLeafsetCheck* ck, const BuildLeafSet* node, 260 int mark_self) { 261 size_t i; 262 if (!ck || !node) return BUILD_ERR; 263 if (mark_self) { 264 int already_seen = 0; 265 if (leafset_check_mark_visited(ck, node->id, &already_seen) != BUILD_OK) 266 return BUILD_ERR; 267 if (already_seen) return BUILD_OK; 268 } 269 for (i = 0; i < node->n_sources; ++i) { 270 if (leafset_check_source(ck, &node->sources[i]) != BUILD_OK) 271 return BUILD_ERR; 272 } 273 for (i = 0; i < node->n_globs; ++i) { 274 if (leafset_check_glob(ck, &node->globs[i]) != BUILD_OK) 275 return BUILD_ERR; 276 } 277 for (i = 0; i < node->n_children; ++i) { 278 if (leafset_check_walk(ck, node->children[i], 1) != BUILD_OK) 279 return BUILD_ERR; 280 } 281 return BUILD_OK; 282 } 283 284 static int build_leafset_check_consistent(KitBuildCoordinator* c, 285 const BuildLeafSet* root, 286 int root_has_id, char* err, 287 size_t errcap) { 288 BuildLeafsetCheck ck; 289 int ok; 290 if (!c || !root) return BUILD_ERR; 291 memset(&ck, 0, sizeof ck); 292 ck.heap = c->ctx->heap; 293 ck.err = err; 294 ck.errcap = errcap; 295 ok = leafset_check_walk(&ck, root, root_has_id); 296 if (ck.sources) 297 ck.heap->free(ck.heap, ck.sources, ck.cap_sources * sizeof ck.sources[0]); 298 if (ck.globs) 299 ck.heap->free(ck.heap, ck.globs, ck.cap_globs * sizeof ck.globs[0]); 300 if (ck.visited) 301 ck.heap->free(ck.heap, ck.visited, ck.cap_visited * sizeof ck.visited[0]); 302 return ok; 303 } 304 305 static int shallow_direct_match(KitBuildCoordinator* c, 306 const BuildShallowTrace* st, 307 const BuildConfig* cfg, 308 const uint8_t argv_id[BUILD_HASH_LEN]) { 309 uint8_t recipe[BUILD_HASH_LEN]; 310 size_t i; 311 if (!build_id_eq(st->argv, argv_id)) return 0; 312 if (build_coord_recipe_id(c, kit_slice_cstr(st->target), recipe) != 313 BUILD_OK || 314 !build_id_eq(recipe, st->recipe)) 315 return 0; 316 for (i = 0; i < st->n_configs; ++i) { 317 if (!config_observation_match(cfg, &st->configs[i])) return 0; 318 } 319 for (i = 0; i < st->n_sources; ++i) { 320 uint8_t blob[BUILD_HASH_LEN]; 321 int present = 0; 322 if (build_coord_source_hash_target(c, kit_slice_cstr(st->target), 323 kit_slice_cstr(st->sources[i].path), 324 blob, &present) != BUILD_OK) 325 return 0; 326 if (st->sources[i].absent) { 327 if (present) return 0; 328 } else if (!present || !build_id_eq(blob, st->sources[i].blob)) { 329 return 0; 330 } 331 } 332 for (i = 0; i < st->n_globs; ++i) { 333 uint8_t hash[BUILD_HASH_LEN]; 334 if (build_coord_glob_target(c, kit_slice_cstr(st->target), 335 kit_slice_cstr(st->globs[i].pattern), hash, 336 NULL, NULL) != BUILD_OK) 337 return 0; 338 if (!build_id_eq(hash, st->globs[i].result_hash)) return 0; 339 } 340 for (i = 0; i < st->n_blobs; ++i) { 341 if (kit_cas_has_blob(c->cas, st->blobs[i].blob) != KIT_OK) return 0; 342 } 343 return 1; 344 } 345 346 static int try_shallow_trace(KitBuildCoordinator* c, KitSlice target, 347 const BuildShallowTrace* st, 348 const BuildConfig* cfg, const BuildArgv* argv, 349 const uint8_t argv_id[BUILD_HASH_LEN], 350 const BuildChainFrame* chain, 351 BuildResolved* out) { 352 BuildDepEdge deps_copy[128]; 353 const BuildLeafSet* child_leafsets[128]; 354 BuildDepLog log; 355 size_t i; 356 if (!shallow_direct_match(c, st, cfg, argv_id)) return BUILD_ERR; 357 if (st->n_deps > sizeof deps_copy / sizeof deps_copy[0] || 358 st->n_deps > sizeof child_leafsets / sizeof child_leafsets[0]) 359 return BUILD_ERR; 360 for (i = 0; i < st->n_deps; ++i) { 361 BuildConfigEntry dep_cfg_entries[128]; 362 BuildConfigEntry overlay_entries[64]; 363 char dep_argv_entries[64][BUILD_VAL_MAX]; 364 BuildConfig dep_cfg, overlay_cfg; 365 BuildArgv dep_argv; 366 BuildResolved dep_r; 367 build_config_init(&dep_cfg, dep_cfg_entries, 368 sizeof dep_cfg_entries / sizeof dep_cfg_entries[0]); 369 build_config_init(&overlay_cfg, overlay_entries, 370 sizeof overlay_entries / sizeof overlay_entries[0]); 371 build_argv_init(&dep_argv, dep_argv_entries, 372 sizeof dep_argv_entries / sizeof dep_argv_entries[0]); 373 if (build_coord_config_by_id(c, st->deps[i].overlay_id, &overlay_cfg) != 374 BUILD_OK || 375 build_config_overlay_map(cfg, &overlay_cfg, &dep_cfg) != BUILD_OK || 376 build_coord_argv_by_id(c, st->deps[i].argv_id, &dep_argv) != 377 BUILD_OK || 378 build_resolve(c, kit_slice_cstr(st->deps[i].name), &dep_cfg, &dep_argv, 379 chain, &dep_r) != BUILD_OK || 380 !build_id_eq(dep_r.output_tree, st->deps[i].output_tree) || 381 !dep_r.leafset) 382 return BUILD_ERR; 383 deps_copy[i] = st->deps[i]; 384 child_leafsets[i] = dep_r.leafset; 385 } 386 if (build_materialize(c, st->output, out->path, sizeof out->path) != BUILD_OK) 387 return BUILD_ERR; 388 memcpy(out->output_tree, st->output, BUILD_HASH_LEN); 389 memset(&log, 0, sizeof log); 390 log.configs = st->configs; 391 log.n_configs = st->n_configs; 392 log.sources = st->sources; 393 log.n_sources = st->n_sources; 394 log.globs = st->globs; 395 log.n_globs = st->n_globs; 396 log.blobs = st->blobs; 397 log.n_blobs = st->n_blobs; 398 log.deps = deps_copy; 399 log.n_deps = st->n_deps; 400 log.child_leafsets = child_leafsets; 401 log.n_children = st->n_deps; 402 return build_runner_record_traces(c, target, argv, &log, 403 out->output_tree, &out->leafset); 404 } 405 406 static int try_test_shallow_trace(KitBuildCoordinator* c, KitSlice target, 407 const BuildShallowTrace* st, 408 const BuildConfig* cfg, 409 const BuildArgv* argv, 410 const uint8_t argv_id[BUILD_HASH_LEN], 411 const BuildChainFrame* chain, 412 BuildTestResolved* out) { 413 BuildDepEdge deps_copy[128]; 414 const BuildLeafSet* child_leafsets[128]; 415 BuildDepLog log; 416 size_t i; 417 if (!shallow_direct_match(c, st, cfg, argv_id)) return BUILD_ERR; 418 if (st->n_deps > sizeof deps_copy / sizeof deps_copy[0] || 419 st->n_deps > sizeof child_leafsets / sizeof child_leafsets[0]) 420 return BUILD_ERR; 421 for (i = 0; i < st->n_deps; ++i) { 422 BuildConfigEntry dep_cfg_entries[128]; 423 BuildConfigEntry overlay_entries[64]; 424 char dep_argv_entries[64][BUILD_VAL_MAX]; 425 BuildConfig dep_cfg, overlay_cfg; 426 BuildArgv dep_argv; 427 BuildResolved dep_r; 428 build_config_init(&dep_cfg, dep_cfg_entries, 429 sizeof dep_cfg_entries / sizeof dep_cfg_entries[0]); 430 build_config_init(&overlay_cfg, overlay_entries, 431 sizeof overlay_entries / sizeof overlay_entries[0]); 432 build_argv_init(&dep_argv, dep_argv_entries, 433 sizeof dep_argv_entries / sizeof dep_argv_entries[0]); 434 if (build_coord_config_by_id(c, st->deps[i].overlay_id, &overlay_cfg) != 435 BUILD_OK || 436 build_config_overlay_map(cfg, &overlay_cfg, &dep_cfg) != BUILD_OK || 437 build_coord_argv_by_id(c, st->deps[i].argv_id, &dep_argv) != 438 BUILD_OK || 439 build_resolve(c, kit_slice_cstr(st->deps[i].name), &dep_cfg, &dep_argv, 440 chain, &dep_r) != BUILD_OK || 441 !build_id_eq(dep_r.output_tree, st->deps[i].output_tree) || 442 !dep_r.leafset) 443 return BUILD_ERR; 444 deps_copy[i] = st->deps[i]; 445 child_leafsets[i] = dep_r.leafset; 446 } 447 if (build_materialize(c, st->output, out->path, sizeof out->path) != BUILD_OK) 448 return BUILD_ERR; 449 memcpy(out->result_tree, st->output, BUILD_HASH_LEN); 450 out->status = KIT_TEST_PASS; 451 out->exit_code = 0; 452 memset(&log, 0, sizeof log); 453 log.configs = st->configs; 454 log.n_configs = st->n_configs; 455 log.sources = st->sources; 456 log.n_sources = st->n_sources; 457 log.globs = st->globs; 458 log.n_globs = st->n_globs; 459 log.blobs = st->blobs; 460 log.n_blobs = st->n_blobs; 461 log.deps = deps_copy; 462 log.n_deps = st->n_deps; 463 log.child_leafsets = child_leafsets; 464 log.n_children = st->n_deps; 465 return build_runner_record_test_traces(c, target, argv, &log, 466 out->result_tree, &out->leafset); 467 } 468 469 static int chain_has(const BuildChainFrame* f, BuildActionKind action, 470 KitSlice target, 471 const uint8_t config_id[BUILD_HASH_LEN], 472 const uint8_t argv_id[BUILD_HASH_LEN]) { 473 for (; f; f = f->parent) { 474 if (f->action == action && strlen(f->target) == target.len && 475 memcmp(f->target, target.s, target.len) == 0 && 476 build_id_eq(f->config_id, config_id) && build_id_eq(f->argv_id, argv_id)) 477 return 1; 478 } 479 return 0; 480 } 481 482 int build_chain_extend(KitBuildCoordinator* c, const BuildChainFrame* parent, 483 BuildActionKind action, KitSlice target, 484 const uint8_t config_id[BUILD_HASH_LEN], 485 const uint8_t argv_id[BUILD_HASH_LEN], 486 const BuildChainFrame** out, char* err, size_t errcap) { 487 BuildChainFrame* f; 488 if (!c || !config_id || !argv_id || !out) return BUILD_ERR; 489 *out = NULL; 490 if (chain_has(parent, action, target, config_id, argv_id)) { 491 if (err && errcap) snprintf(err, errcap, "dependency cycle at %.*s", 492 KIT_SLICE_ARG(target)); 493 return BUILD_ERR; 494 } 495 f = (BuildChainFrame*)c->ctx->heap->alloc(c->ctx->heap, sizeof *f, 496 _Alignof(BuildChainFrame)); 497 if (!f) return BUILD_ERR; 498 memset(f, 0, sizeof *f); 499 f->parent = parent; 500 f->action = action; 501 if (target_copy(target, f->target) != BUILD_OK) return BUILD_ERR; 502 memcpy(f->config_id, config_id, BUILD_HASH_LEN); 503 memcpy(f->argv_id, argv_id, BUILD_HASH_LEN); 504 *out = f; 505 return BUILD_OK; 506 } 507 508 int build_materialize(KitBuildCoordinator* c, 509 const uint8_t tree_id[BUILD_HASH_LEN], char* path_out, 510 size_t cap) { 511 char tmp_dir[BUILD_PATH_MAX]; 512 if (!c || !tree_id || !path_out) return BUILD_ERR; 513 if (build_store_cache_lookup(&c->store, tree_id, path_out, cap) == BUILD_OK) 514 return BUILD_OK; 515 if (build_store_cache_materialize(&c->store, tree_id, path_out, cap) == 516 BUILD_OK) 517 return BUILD_OK; 518 if (c->opts.n_object_remotes && c->host.exec) { 519 if (path_join2(tmp_dir, sizeof tmp_dir, c->store.root, "tmp") == 520 BUILD_OK && 521 build_remote_fetch(c->ctx, c->host.exec, c->opts.object_remotes, 522 c->opts.n_object_remotes, c->cas, 523 kit_slice_cstr(tmp_dir), BUILD_REMOTE_TREE, 524 tree_id) == BUILD_OK) { 525 build_coord_stat_bump(c, BUILD_STAT_OBJECT_FETCH); 526 if (build_store_cache_materialize(&c->store, tree_id, path_out, cap) == 527 BUILD_OK) 528 return BUILD_OK; 529 } 530 } 531 build_coord_stat_bump(c, BUILD_STAT_MATERIALIZE_MISS); 532 return BUILD_ERR; 533 } 534 535 static int verify_cached_hit(KitBuildCoordinator* c, KitSlice target, 536 const BuildConfig* cfg, const BuildArgv* argv, 537 const BuildChainFrame* chain, 538 const uint8_t expected[BUILD_HASH_LEN], 539 BuildResolved* out) { 540 BuildResolved fresh; 541 char want[BUILD_HEX_LEN], got[BUILD_HEX_LEN]; 542 if (!c || !expected || !out) return BUILD_ERR; 543 if (!c->opts.verify) return BUILD_OK; 544 memset(&fresh, 0, sizeof fresh); 545 if (build_run_recipe_probe(c, target, cfg, argv, chain, &fresh) != BUILD_OK) 546 return BUILD_ERR; 547 if (!build_id_eq(fresh.output_tree, expected)) { 548 kit_hex_encode(want, expected, BUILD_HASH_LEN); 549 kit_hex_encode(got, fresh.output_tree, BUILD_HASH_LEN); 550 build_diagf(c->ctx, 551 "build: verify mismatch for %.*s: cached %s fresh %s", 552 KIT_SLICE_ARG(target), want, got); 553 return BUILD_ERR; 554 } 555 return BUILD_OK; 556 } 557 558 static int blob_from_materialized_file(KitBuildCoordinator* c, const char* dir, 559 const char* name, 560 uint8_t out[BUILD_HASH_LEN]) { 561 char path[BUILD_PATH_MAX]; 562 KitFileData fd; 563 KitBlobInfo bi; 564 if (!c || !dir || !name || !out) return BUILD_ERR; 565 if (path_join2(path, sizeof path, dir, name) != BUILD_OK) return BUILD_ERR; 566 fd.data = NULL; 567 fd.size = 0; 568 fd.token = NULL; 569 if (!c->host.cas_host || !c->host.cas_host->file_io || 570 !c->host.cas_host->file_io->read_all || 571 c->host.cas_host->file_io->read_all(c->host.cas_host->file_io->user, path, 572 &fd) != KIT_OK) 573 return BUILD_ERR; 574 if (kit_cas_add_blob(c->cas, fd.data, fd.size, &bi) != KIT_OK) { 575 if (c->host.cas_host->file_io->release) 576 c->host.cas_host->file_io->release(c->host.cas_host->file_io->user, &fd); 577 return BUILD_ERR; 578 } 579 memcpy(out, bi.id, BUILD_HASH_LEN); 580 if (c->host.cas_host->file_io->release) 581 c->host.cas_host->file_io->release(c->host.cas_host->file_io->user, &fd); 582 return BUILD_OK; 583 } 584 585 static int fill_test_stdio_blobs(KitBuildCoordinator* c, BuildTestResolved* r) { 586 if (!c || !r) return BUILD_ERR; 587 return blob_from_materialized_file(c, r->path, "stdout", r->stdout_blob) == 588 BUILD_OK && 589 blob_from_materialized_file(c, r->path, "stderr", r->stderr_blob) == 590 BUILD_OK 591 ? BUILD_OK 592 : BUILD_ERR; 593 } 594 595 static int verify_cached_test_hit(KitBuildCoordinator* c, KitSlice target, 596 const BuildConfig* cfg, 597 const BuildArgv* argv, 598 const BuildChainFrame* chain, 599 const uint8_t expected[BUILD_HASH_LEN]) { 600 BuildTestResolved fresh; 601 char want[BUILD_HEX_LEN], got[BUILD_HEX_LEN]; 602 if (!c || !expected) return BUILD_ERR; 603 if (!c->opts.verify) return BUILD_OK; 604 memset(&fresh, 0, sizeof fresh); 605 if (build_run_test_recipe(c, target, cfg, argv, chain, &fresh, 0) != BUILD_OK) 606 return BUILD_ERR; 607 if (fresh.status != KIT_TEST_PASS || !build_id_eq(fresh.result_tree, expected)) { 608 kit_hex_encode(want, expected, BUILD_HASH_LEN); 609 kit_hex_encode(got, fresh.result_tree, BUILD_HASH_LEN); 610 build_diagf(c->ctx, 611 "build test: verify mismatch for %.*s: cached %s fresh %s", 612 KIT_SLICE_ARG(target), want, got); 613 return BUILD_ERR; 614 } 615 return BUILD_OK; 616 } 617 618 int build_resolve(KitBuildCoordinator* c, KitSlice target, const BuildConfig* cfg, 619 const BuildArgv* argv, const BuildChainFrame* chain, 620 BuildResolved* out) { 621 uint8_t config_id[BUILD_HASH_LEN], argv_id[BUILD_HASH_LEN]; 622 uint8_t target_key[BUILD_HASH_LEN]; 623 const BuildChainFrame* child; 624 BuildRecordRow rows[2u * KIT_BUILD_RECORD_CAP]; 625 BuildTargetRecord rec; 626 size_t i; 627 char err[128]; 628 int pulled_remote = 0; 629 if (!c || !cfg || !argv || !out) return BUILD_ERR; 630 if (build_config_id(c->ctx->heap, cfg, config_id) != BUILD_OK || 631 build_argv_id(c->ctx->heap, argv, argv_id) != BUILD_OK) 632 return BUILD_ERR; 633 if (c->opts.trace) { 634 char cfg_hex[BUILD_HEX_LEN], argv_hex[BUILD_HEX_LEN]; 635 kit_hex_encode(cfg_hex, config_id, BUILD_HASH_LEN); 636 kit_hex_encode(argv_hex, argv_id, BUILD_HASH_LEN); 637 build_coord_tracef(c, "resolve-start action=build target=%.*s root=%d config=%s argv=%s", 638 KIT_SLICE_ARG(target), chain ? 0 : 1, cfg_hex, 639 argv_hex); 640 } 641 if (build_chain_extend(c, chain, BUILD_ACTION_BUILD, target, config_id, 642 argv_id, &child, err, sizeof err) != BUILD_OK) { 643 build_diagf(c->ctx, "build: %s", err); 644 return BUILD_ERR; 645 } 646 if (build_target_key(target, target_key) == BUILD_OK) { 647 scan_record: 648 memset(&rec, 0, sizeof rec); 649 rec.rows = rows; 650 rec.cap_rows = sizeof rows / sizeof rows[0]; 651 if (build_store_record_load(&c->store, target_key, target, &rec) == 652 BUILD_OK) { 653 if (rec.n_rows == 0u && !pulled_remote) { 654 int pulled_now = 0; 655 pulled_remote = 1; 656 if (build_coord_trace_remote_pull_once(c, target, &pulled_now) == 657 BUILD_OK && 658 pulled_now) 659 goto scan_record; 660 } 661 for (i = 0; i < rec.n_rows; ++i) { 662 KitFileData fd; 663 BuildDeepTrace dt; 664 const BuildLeafSet* leaf = NULL; 665 int match = 0; 666 if (rec.rows[i].kind != (uint8_t)BUILD_TRACE_DEEP) continue; 667 fd.data = NULL; 668 fd.size = 0; 669 fd.token = NULL; 670 if (build_store_get_trace(&c->store, rec.rows[i].trace_id, &fd) != 671 BUILD_OK) 672 continue; 673 if (c->opts.trace) { 674 char trace_hex[BUILD_HEX_LEN]; 675 kit_hex_encode(trace_hex, rec.rows[i].trace_id, BUILD_HASH_LEN); 676 build_coord_tracef(c, "deep-candidate target=%.*s trace=%s", 677 KIT_SLICE_ARG(target), trace_hex); 678 } 679 memset(&dt, 0, sizeof dt); 680 err[0] = '\0'; 681 if (build_deep_parse(fd.data, fd.size, &dt, NULL, 0) == BUILD_OK && 682 strlen(dt.target) == target.len && 683 memcmp(dt.target, target.s, target.len) == 0 && 684 build_id_eq(dt.argv, argv_id) && 685 build_coord_deepset_load(c, dt.deepset, &leaf) == BUILD_OK && 686 build_leafset_check_consistent(c, leaf, 1, err, sizeof err) == 687 BUILD_OK && 688 build_leafset_refresh(c, leaf, cfg, &match) == BUILD_OK && match && 689 build_materialize(c, dt.output, out->path, sizeof out->path) == 690 BUILD_OK) { 691 memcpy(out->output_tree, dt.output, BUILD_HASH_LEN); 692 out->leafset = leaf; 693 if (verify_cached_hit(c, target, cfg, argv, child, dt.output, out) != 694 BUILD_OK) { 695 build_store_release(&c->store, &fd); 696 return BUILD_ERR; 697 } 698 if (c->opts.trace) { 699 char out_hex[BUILD_HEX_LEN]; 700 kit_hex_encode(out_hex, dt.output, BUILD_HASH_LEN); 701 build_coord_tracef(c, "deep-hit target=%.*s output=%s", 702 KIT_SLICE_ARG(target), out_hex); 703 } 704 build_store_release(&c->store, &fd); 705 build_coord_stat_bump(c, BUILD_STAT_DEEP_HIT); 706 return BUILD_OK; 707 } 708 if (c->opts.trace) 709 build_coord_tracef(c, "deep-miss target=%.*s reason=%s", 710 KIT_SLICE_ARG(target), 711 err[0] ? "malformed" : "no-match"); 712 if (err[0]) 713 KIT_LOGD("skip deep trace for %.*s: %s", KIT_SLICE_ARG(target), err); 714 err[0] = '\0'; 715 build_store_release(&c->store, &fd); 716 } 717 for (i = 0; i < rec.n_rows; ++i) { 718 KitFileData fd; 719 BuildConfigLeaf configs[BUILD_RECIPE_CONFIG_CAP]; 720 BuildSourceLeaf sources[BUILD_RECIPE_SOURCE_CAP]; 721 BuildGlobLeaf globs[BUILD_RECIPE_GLOB_CAP]; 722 BuildBlobLeaf blobs[BUILD_RECIPE_BLOB_CAP]; 723 BuildDepEdge deps[BUILD_RECIPE_DEP_CAP]; 724 BuildShallowTrace st; 725 size_t rows; 726 if (rec.rows[i].kind != (uint8_t)BUILD_TRACE_SHALLOW) continue; 727 fd.data = NULL; 728 fd.size = 0; 729 fd.token = NULL; 730 if (build_store_get_trace(&c->store, rec.rows[i].trace_id, &fd) != 731 BUILD_OK) 732 continue; 733 if (c->opts.trace) { 734 char trace_hex[BUILD_HEX_LEN]; 735 kit_hex_encode(trace_hex, rec.rows[i].trace_id, BUILD_HASH_LEN); 736 build_coord_tracef(c, "shallow-candidate target=%.*s trace=%s", 737 KIT_SLICE_ARG(target), trace_hex); 738 } 739 rows = count_lines(fd.data, fd.size); 740 memset(&st, 0, sizeof st); 741 st.configs = configs; 742 st.cap_configs = sizeof configs / sizeof configs[0]; 743 st.sources = sources; 744 st.cap_sources = sizeof sources / sizeof sources[0]; 745 st.globs = globs; 746 st.cap_globs = sizeof globs / sizeof globs[0]; 747 st.blobs = blobs; 748 st.cap_blobs = sizeof blobs / sizeof blobs[0]; 749 st.deps = deps; 750 st.cap_deps = sizeof deps / sizeof deps[0]; 751 if (rows <= sizeof configs / sizeof configs[0] && 752 build_shallow_parse(fd.data, fd.size, &st, NULL, 0) == BUILD_OK && 753 strlen(st.target) == target.len && 754 memcmp(st.target, target.s, target.len) == 0 && 755 try_shallow_trace(c, target, &st, cfg, argv, argv_id, child, out) == 756 BUILD_OK) { 757 if (verify_cached_hit(c, target, cfg, argv, child, st.output, out) != 758 BUILD_OK) { 759 build_store_release(&c->store, &fd); 760 return BUILD_ERR; 761 } 762 if (c->opts.trace) { 763 char out_hex[BUILD_HEX_LEN]; 764 kit_hex_encode(out_hex, st.output, BUILD_HASH_LEN); 765 build_coord_tracef(c, "shallow-hit target=%.*s output=%s", 766 KIT_SLICE_ARG(target), out_hex); 767 } 768 build_store_release(&c->store, &fd); 769 build_coord_stat_bump(c, BUILD_STAT_SHALLOW_HIT); 770 return BUILD_OK; 771 } 772 if (c->opts.trace) 773 build_coord_tracef(c, "shallow-miss target=%.*s reason=no-match", 774 KIT_SLICE_ARG(target)); 775 build_store_release(&c->store, &fd); 776 } 777 } 778 } 779 build_coord_tracef(c, "recipe-run target=%.*s", KIT_SLICE_ARG(target)); 780 return build_run_recipe(c, target, cfg, argv, child, out); 781 } 782 783 int build_test_resolve(KitBuildCoordinator* c, KitSlice target, 784 const BuildConfig* cfg, const BuildArgv* argv, 785 const BuildChainFrame* chain, BuildTestResolved* out) { 786 uint8_t config_id[BUILD_HASH_LEN], argv_id[BUILD_HASH_LEN]; 787 uint8_t target_key[BUILD_HASH_LEN]; 788 const BuildChainFrame* child; 789 BuildRecordRow rows[2u * KIT_BUILD_RECORD_CAP]; 790 BuildTargetRecord rec; 791 size_t i; 792 char err[128]; 793 int pulled_remote = 0; 794 if (!c || !cfg || !argv || !out) return BUILD_ERR; 795 if (build_config_id(c->ctx->heap, cfg, config_id) != BUILD_OK || 796 build_argv_id(c->ctx->heap, argv, argv_id) != BUILD_OK) 797 return BUILD_ERR; 798 if (c->opts.trace) { 799 char cfg_hex[BUILD_HEX_LEN], argv_hex[BUILD_HEX_LEN]; 800 kit_hex_encode(cfg_hex, config_id, BUILD_HASH_LEN); 801 kit_hex_encode(argv_hex, argv_id, BUILD_HASH_LEN); 802 build_coord_tracef(c, "resolve-start action=test target=%.*s root=%d config=%s argv=%s", 803 KIT_SLICE_ARG(target), chain ? 0 : 1, cfg_hex, 804 argv_hex); 805 } 806 if (build_chain_extend(c, chain, BUILD_ACTION_TEST, target, config_id, 807 argv_id, &child, err, sizeof err) != BUILD_OK) { 808 build_diagf(c->ctx, "build test: %s", err); 809 return BUILD_ERR; 810 } 811 if (build_test_target_key(target, target_key) == BUILD_OK) { 812 scan_record: 813 memset(&rec, 0, sizeof rec); 814 rec.rows = rows; 815 rec.cap_rows = sizeof rows / sizeof rows[0]; 816 if (build_store_record_load(&c->store, target_key, target, &rec) == 817 BUILD_OK) { 818 if (rec.n_rows == 0u && !pulled_remote) { 819 int pulled_now = 0; 820 pulled_remote = 1; 821 if (build_coord_trace_remote_pull_once(c, target, &pulled_now) == 822 BUILD_OK && 823 pulled_now) 824 goto scan_record; 825 } 826 for (i = 0; i < rec.n_rows; ++i) { 827 KitFileData fd; 828 BuildDeepTrace dt; 829 const BuildLeafSet* leaf = NULL; 830 int match = 0; 831 if (rec.rows[i].kind != (uint8_t)BUILD_TRACE_DEEP) continue; 832 fd.data = NULL; 833 fd.size = 0; 834 fd.token = NULL; 835 if (build_store_get_trace(&c->store, rec.rows[i].trace_id, &fd) != 836 BUILD_OK) 837 continue; 838 if (c->opts.trace) { 839 char trace_hex[BUILD_HEX_LEN]; 840 kit_hex_encode(trace_hex, rec.rows[i].trace_id, BUILD_HASH_LEN); 841 build_coord_tracef(c, "deep-candidate target=%.*s trace=%s", 842 KIT_SLICE_ARG(target), trace_hex); 843 } 844 memset(&dt, 0, sizeof dt); 845 err[0] = '\0'; 846 if (build_test_deep_parse(fd.data, fd.size, &dt, NULL, 0) == BUILD_OK && 847 strlen(dt.target) == target.len && 848 memcmp(dt.target, target.s, target.len) == 0 && 849 build_id_eq(dt.argv, argv_id) && 850 build_coord_deepset_load(c, dt.deepset, &leaf) == BUILD_OK && 851 build_leafset_check_consistent(c, leaf, 1, err, sizeof err) == 852 BUILD_OK && 853 build_leafset_refresh(c, leaf, cfg, &match) == BUILD_OK && match && 854 build_materialize(c, dt.output, out->path, sizeof out->path) == 855 BUILD_OK) { 856 out->status = KIT_TEST_PASS; 857 out->exit_code = 0; 858 memcpy(out->result_tree, dt.output, BUILD_HASH_LEN); 859 out->leafset = leaf; 860 if (fill_test_stdio_blobs(c, out) != BUILD_OK || 861 verify_cached_test_hit(c, target, cfg, argv, child, dt.output) != 862 BUILD_OK) { 863 build_store_release(&c->store, &fd); 864 return BUILD_ERR; 865 } 866 if (c->opts.trace) { 867 char out_hex[BUILD_HEX_LEN]; 868 kit_hex_encode(out_hex, dt.output, BUILD_HASH_LEN); 869 build_coord_tracef(c, "deep-hit target=%.*s output=%s", 870 KIT_SLICE_ARG(target), out_hex); 871 } 872 build_store_release(&c->store, &fd); 873 build_coord_stat_bump(c, BUILD_STAT_TEST_CACHE_HIT); 874 return BUILD_OK; 875 } 876 if (c->opts.trace) 877 build_coord_tracef(c, "deep-miss target=%.*s reason=%s", 878 KIT_SLICE_ARG(target), 879 err[0] ? "malformed" : "no-match"); 880 if (err[0]) 881 KIT_LOGD("skip test deep trace for %.*s: %s", KIT_SLICE_ARG(target), 882 err); 883 err[0] = '\0'; 884 build_store_release(&c->store, &fd); 885 } 886 for (i = 0; i < rec.n_rows; ++i) { 887 KitFileData fd; 888 BuildConfigLeaf configs[BUILD_RECIPE_CONFIG_CAP]; 889 BuildSourceLeaf sources[BUILD_RECIPE_SOURCE_CAP]; 890 BuildGlobLeaf globs[BUILD_RECIPE_GLOB_CAP]; 891 BuildBlobLeaf blobs[BUILD_RECIPE_BLOB_CAP]; 892 BuildDepEdge deps[BUILD_RECIPE_DEP_CAP]; 893 BuildShallowTrace st; 894 size_t nrows; 895 if (rec.rows[i].kind != (uint8_t)BUILD_TRACE_SHALLOW) continue; 896 fd.data = NULL; 897 fd.size = 0; 898 fd.token = NULL; 899 if (build_store_get_trace(&c->store, rec.rows[i].trace_id, &fd) != 900 BUILD_OK) 901 continue; 902 if (c->opts.trace) { 903 char trace_hex[BUILD_HEX_LEN]; 904 kit_hex_encode(trace_hex, rec.rows[i].trace_id, BUILD_HASH_LEN); 905 build_coord_tracef(c, "shallow-candidate target=%.*s trace=%s", 906 KIT_SLICE_ARG(target), trace_hex); 907 } 908 nrows = count_lines(fd.data, fd.size); 909 memset(&st, 0, sizeof st); 910 st.configs = configs; 911 st.cap_configs = sizeof configs / sizeof configs[0]; 912 st.sources = sources; 913 st.cap_sources = sizeof sources / sizeof sources[0]; 914 st.globs = globs; 915 st.cap_globs = sizeof globs / sizeof globs[0]; 916 st.blobs = blobs; 917 st.cap_blobs = sizeof blobs / sizeof blobs[0]; 918 st.deps = deps; 919 st.cap_deps = sizeof deps / sizeof deps[0]; 920 if (nrows <= sizeof configs / sizeof configs[0] && 921 build_test_shallow_parse(fd.data, fd.size, &st, NULL, 0) == 922 BUILD_OK && 923 strlen(st.target) == target.len && 924 memcmp(st.target, target.s, target.len) == 0 && 925 try_test_shallow_trace(c, target, &st, cfg, argv, argv_id, child, 926 out) == BUILD_OK) { 927 if (fill_test_stdio_blobs(c, out) != BUILD_OK || 928 verify_cached_test_hit(c, target, cfg, argv, child, st.output) != 929 BUILD_OK) { 930 build_store_release(&c->store, &fd); 931 return BUILD_ERR; 932 } 933 if (c->opts.trace) { 934 char out_hex[BUILD_HEX_LEN]; 935 kit_hex_encode(out_hex, st.output, BUILD_HASH_LEN); 936 build_coord_tracef(c, "shallow-hit target=%.*s output=%s", 937 KIT_SLICE_ARG(target), out_hex); 938 } 939 build_store_release(&c->store, &fd); 940 build_coord_stat_bump(c, BUILD_STAT_TEST_CACHE_HIT); 941 return BUILD_OK; 942 } 943 if (c->opts.trace) 944 build_coord_tracef(c, "shallow-miss target=%.*s reason=no-match", 945 KIT_SLICE_ARG(target)); 946 build_store_release(&c->store, &fd); 947 } 948 } 949 } 950 build_coord_tracef(c, "recipe-run target=%.*s", KIT_SLICE_ARG(target)); 951 return build_run_test_recipe(c, target, cfg, argv, child, out, 1); 952 } 953 954 int build_dispatch(KitBuildCoordinator* c, KitSlice target, 955 const BuildConfig* cfg, const BuildArgv* argv, 956 const BuildChainFrame* chain, 957 BuildTargetFuture** out_future, char* err, size_t errcap) { 958 uint8_t config_id[BUILD_HASH_LEN], argv_id[BUILD_HASH_LEN]; 959 const BuildChainFrame* child; 960 BuildResolved r; 961 int fresh; 962 if (!c || !cfg || !argv || !out_future) return BUILD_ERR; 963 if (build_config_id(c->ctx->heap, cfg, config_id) != BUILD_OK || 964 build_argv_id(c->ctx->heap, argv, argv_id) != BUILD_OK) 965 return BUILD_ERR; 966 if (build_chain_extend(c, chain, BUILD_ACTION_BUILD, target, config_id, 967 argv_id, &child, err, errcap) != BUILD_OK) 968 return BUILD_ERR; 969 if (build_coord_target_intern(c, target, config_id, argv_id, out_future, 970 &fresh) != BUILD_OK) 971 return BUILD_ERR; 972 if (!fresh) return BUILD_OK; 973 memset(&r, 0, sizeof r); 974 if (build_resolve(c, target, cfg, argv, chain, &r) == BUILD_OK) { 975 (void)child; 976 build_coord_target_complete(c, *out_future, &r); 977 return BUILD_OK; 978 } 979 build_coord_target_fail(c, *out_future); 980 if (err && errcap) snprintf(err, errcap, "build dispatch failed"); 981 return BUILD_ERR; 982 } 983 984 int build_leafset_union(KitBuildCoordinator* c, const BuildLeafSet* direct, 985 const BuildDepEdge* deps, 986 const BuildLeafSet* const* children, size_t nchildren, 987 const BuildLeafSet** out) { 988 BuildDeepSet ds; 989 BuildLeafSet leaf; 990 BuildLeafSet check_root; 991 BuildConfigLeaf* projected_configs = NULL; 992 size_t n_projected_configs = 0; 993 size_t cap_projected_configs = 0; 994 uint8_t(*child_ids)[BUILD_HASH_LEN] = NULL; 995 const BuildLeafSet** child_ptrs = NULL; 996 KitWriter* w = NULL; 997 const uint8_t* bytes; 998 size_t len, i; 999 KitBlobInfo bi; 1000 char err[128]; 1001 int ok = BUILD_ERR; 1002 if (!c || !direct || !out) return BUILD_ERR; 1003 if (nchildren && !children) return BUILD_ERR; 1004 if (nchildren && !deps) return BUILD_ERR; 1005 if (projected_config_collect(c, direct, deps, children, nchildren, 1006 &projected_configs, &n_projected_configs, 1007 &cap_projected_configs) != BUILD_OK) 1008 goto out; 1009 if (nchildren) { 1010 child_ids = (uint8_t(*)[BUILD_HASH_LEN])c->ctx->heap->alloc( 1011 c->ctx->heap, nchildren * sizeof *child_ids, _Alignof(uint8_t)); 1012 child_ptrs = (const BuildLeafSet**)c->ctx->heap->alloc( 1013 c->ctx->heap, nchildren * sizeof *child_ptrs, 1014 _Alignof(const BuildLeafSet*)); 1015 if (!child_ids || !child_ptrs) goto out; 1016 for (i = 0; i < nchildren; ++i) { 1017 if (!children[i]) goto out; 1018 memcpy(child_ids[i], children[i]->id, BUILD_HASH_LEN); 1019 child_ptrs[i] = children[i]; 1020 } 1021 } 1022 memset(&check_root, 0, sizeof check_root); 1023 snprintf(check_root.target, sizeof check_root.target, "%s", direct->target); 1024 memcpy(check_root.recipe, direct->recipe, BUILD_HASH_LEN); 1025 check_root.configs = projected_configs; 1026 check_root.n_configs = n_projected_configs; 1027 check_root.sources = direct->sources; 1028 check_root.n_sources = direct->n_sources; 1029 check_root.globs = direct->globs; 1030 check_root.n_globs = direct->n_globs; 1031 check_root.blobs = direct->blobs; 1032 check_root.n_blobs = direct->n_blobs; 1033 check_root.children = child_ptrs; 1034 check_root.n_children = nchildren; 1035 if (build_leafset_check_consistent(c, &check_root, 0, err, sizeof err) != 1036 BUILD_OK) { 1037 build_diagf(c->ctx, "build: inconsistent deepset closure: %s", err); 1038 goto out; 1039 } 1040 memset(&ds, 0, sizeof ds); 1041 snprintf(ds.target, sizeof ds.target, "%s", direct->target); 1042 memcpy(ds.recipe, direct->recipe, BUILD_HASH_LEN); 1043 ds.configs = projected_configs; 1044 ds.n_configs = n_projected_configs; 1045 ds.sources = direct->sources; 1046 ds.n_sources = direct->n_sources; 1047 ds.globs = direct->globs; 1048 ds.n_globs = direct->n_globs; 1049 ds.blobs = direct->blobs; 1050 ds.n_blobs = direct->n_blobs; 1051 ds.children = child_ids; 1052 ds.n_children = nchildren; 1053 if (kit_writer_mem(c->ctx->heap, &w) != KIT_OK || !w) goto out; 1054 if (build_deepset_emit(&ds, w, err, sizeof err) != BUILD_OK || 1055 kit_writer_status(w) != KIT_OK) 1056 goto out; 1057 bytes = kit_writer_mem_bytes(w, &len); 1058 build_deepset_id(bytes, len, leaf.id); 1059 if (kit_cas_add_blob(c->cas, bytes, len, &bi) != KIT_OK || 1060 !build_id_eq(bi.id, leaf.id)) 1061 goto out; 1062 memset(&leaf, 0, sizeof leaf); 1063 build_deepset_id(bytes, len, leaf.id); 1064 snprintf(leaf.target, sizeof leaf.target, "%s", direct->target); 1065 memcpy(leaf.recipe, direct->recipe, BUILD_HASH_LEN); 1066 leaf.configs = projected_configs; 1067 leaf.n_configs = n_projected_configs; 1068 leaf.sources = direct->sources; 1069 leaf.n_sources = direct->n_sources; 1070 leaf.globs = direct->globs; 1071 leaf.n_globs = direct->n_globs; 1072 leaf.blobs = direct->blobs; 1073 leaf.n_blobs = direct->n_blobs; 1074 leaf.children = child_ptrs; 1075 leaf.n_children = nchildren; 1076 if (build_coord_leafset_intern(c, &leaf, out) != BUILD_OK) goto out; 1077 ok = BUILD_OK; 1078 out: 1079 if (w) kit_writer_close(w); 1080 if (child_ids) 1081 c->ctx->heap->free(c->ctx->heap, child_ids, 1082 nchildren * sizeof *child_ids); 1083 if (child_ptrs) 1084 c->ctx->heap->free(c->ctx->heap, child_ptrs, 1085 nchildren * sizeof *child_ptrs); 1086 if (projected_configs) 1087 c->ctx->heap->free(c->ctx->heap, projected_configs, 1088 cap_projected_configs * sizeof *projected_configs); 1089 return ok; 1090 } 1091 1092 static int build_leafset_refresh_inner(KitBuildCoordinator* c, 1093 const BuildLeafSet* leafset, 1094 const BuildConfig* cfg, 1095 int check_config, 1096 const char* trace_root, 1097 int* all_match) { 1098 size_t i; 1099 KitSlice target; 1100 uint8_t recipe[BUILD_HASH_LEN]; 1101 int matched_all = 1; 1102 if (!c || !leafset || !cfg || !all_match) return BUILD_ERR; 1103 *all_match = 0; 1104 target = kit_slice_cstr(leafset->target); 1105 if (build_coord_recipe_id(c, target, recipe) != BUILD_OK || 1106 !build_id_eq(recipe, leafset->recipe)) 1107 goto done; 1108 if (check_config) { 1109 for (i = 0; i < leafset->n_configs; ++i) { 1110 int matched = config_observation_match(cfg, &leafset->configs[i]); 1111 if (c->opts.trace) 1112 build_coord_tracef(c, 1113 "deep-config target=%s key=%s scope=root result=%s", 1114 leafset->target, leafset->configs[i].key, 1115 matched ? "match" : "mismatch"); 1116 if (!matched) matched_all = 0; 1117 } 1118 } else if (c->opts.trace) { 1119 for (i = 0; i < leafset->n_configs; ++i) 1120 build_coord_tracef(c, 1121 "deep-config target=%s child=%s key=%s scope=overlay-shielded", 1122 trace_root ? trace_root : leafset->target, 1123 leafset->target, leafset->configs[i].key); 1124 } 1125 for (i = 0; i < leafset->n_sources; ++i) { 1126 uint8_t blob[BUILD_HASH_LEN]; 1127 int present = 0; 1128 if (build_coord_source_hash_target(c, target, 1129 kit_slice_cstr(leafset->sources[i].path), 1130 blob, &present) != BUILD_OK) 1131 return BUILD_ERR; 1132 if (leafset->sources[i].absent) { 1133 if (present) matched_all = 0; 1134 } else if (!present || !build_id_eq(blob, leafset->sources[i].blob)) { 1135 matched_all = 0; 1136 } 1137 } 1138 for (i = 0; i < leafset->n_globs; ++i) { 1139 uint8_t hash[BUILD_HASH_LEN]; 1140 if (build_coord_glob_target(c, target, 1141 kit_slice_cstr(leafset->globs[i].pattern), 1142 hash, NULL, NULL) != BUILD_OK) 1143 return BUILD_ERR; 1144 if (!build_id_eq(hash, leafset->globs[i].result_hash)) matched_all = 0; 1145 } 1146 for (i = 0; i < leafset->n_blobs; ++i) { 1147 if (kit_cas_has_blob(c->cas, leafset->blobs[i].blob) != KIT_OK) 1148 matched_all = 0; 1149 } 1150 for (i = 0; i < leafset->n_children; ++i) { 1151 int child_match = 0; 1152 if (build_leafset_refresh_inner(c, leafset->children[i], cfg, 0, 1153 trace_root ? trace_root : leafset->target, 1154 &child_match) != BUILD_OK) 1155 return BUILD_ERR; 1156 if (!child_match) matched_all = 0; 1157 } 1158 if (matched_all) *all_match = 1; 1159 done: 1160 return BUILD_OK; 1161 } 1162 1163 int build_leafset_refresh(KitBuildCoordinator* c, const BuildLeafSet* leafset, 1164 const BuildConfig* cfg, int* all_match) { 1165 return build_leafset_refresh_inner(c, leafset, cfg, 1, 1166 leafset ? leafset->target : NULL, 1167 all_match); 1168 }