| 7601 | } |
| 7602 | |
| 7603 | static int arch_layers(cbm_store_t *s, const char *project, const char *path, |
| 7604 | cbm_architecture_info_t *out) { |
| 7605 | /* Get boundaries for fan analysis */ |
| 7606 | cbm_cross_pkg_boundary_t *boundaries = NULL; |
| 7607 | int bcount = 0; |
| 7608 | int rc = arch_boundaries(s, project, path, &boundaries, &bcount); |
| 7609 | if (rc != CBM_STORE_OK) { |
| 7610 | return rc; |
| 7611 | } |
| 7612 | |
| 7613 | /* Collect route and entry point packages */ |
| 7614 | char *route_pkgs[CBM_SZ_32]; |
| 7615 | int nrpkgs = |
| 7616 | collect_pkg_names(s, "SELECT qualified_name FROM nodes WHERE project=?1 AND label='Route'", |
| 7617 | project, path, route_pkgs, CBM_SZ_32); |
| 7618 | |
| 7619 | char *entry_pkgs[CBM_SZ_32]; |
| 7620 | int nepkgs = collect_pkg_names(s, |
| 7621 | "SELECT qualified_name FROM nodes WHERE project=?1 AND " |
| 7622 | "json_extract(properties, '$.is_entry_point') = 1", |
| 7623 | project, path, entry_pkgs, CBM_SZ_32); |
| 7624 | |
| 7625 | /* Compute fan-in/out per package */ |
| 7626 | char *all_pkgs[CBM_SZ_64]; |
| 7627 | int fan_in[CBM_SZ_64]; |
| 7628 | int fan_out[CBM_SZ_64]; |
| 7629 | int npkgs = 0; |
| 7630 | memset(fan_in, 0, sizeof(fan_in)); |
| 7631 | memset(fan_out, 0, sizeof(fan_out)); |
| 7632 | |
| 7633 | for (int i = 0; i < bcount; i++) { |
| 7634 | int fi = find_or_add_pkg(all_pkgs, &npkgs, ST_MAX_PKGS, boundaries[i].from); |
| 7635 | if (fi >= 0) { |
| 7636 | fan_out[fi] += boundaries[i].call_count; |
| 7637 | } |
| 7638 | int ti = find_or_add_pkg(all_pkgs, &npkgs, ST_MAX_PKGS, boundaries[i].to); |
| 7639 | if (ti >= 0) { |
| 7640 | fan_in[ti] += boundaries[i].call_count; |
| 7641 | } |
| 7642 | } |
| 7643 | |
| 7644 | /* Also include route/entry packages */ |
| 7645 | for (int i = 0; i < nrpkgs; i++) { |
| 7646 | find_or_add_pkg(all_pkgs, &npkgs, ST_MAX_PKGS, route_pkgs[i]); |
| 7647 | } |
| 7648 | for (int i = 0; i < nepkgs; i++) { |
| 7649 | find_or_add_pkg(all_pkgs, &npkgs, ST_MAX_PKGS, entry_pkgs[i]); |
| 7650 | } |
| 7651 | |
| 7652 | /* Classify each package */ |
| 7653 | out->layers = (npkgs > 0) ? calloc(npkgs, sizeof(cbm_package_layer_t)) : NULL; |
| 7654 | out->layer_count = npkgs; |
| 7655 | for (int i = 0; i < npkgs; i++) { |
| 7656 | bool has_route = pkg_in_list(all_pkgs[i], route_pkgs, nrpkgs); |
| 7657 | bool has_entry = pkg_in_list(all_pkgs[i], entry_pkgs, nepkgs); |
| 7658 | const char *layer; |
| 7659 | const char *reason; |
| 7660 | classify_layer(all_pkgs[i], fan_in[i], fan_out[i], has_route, has_entry, &layer, &reason); |
no test coverage detected