| 4298 | } |
| 4299 | |
| 4300 | static int arch_layers(cbm_store_t *s, const char *project, const char *path, |
| 4301 | cbm_architecture_info_t *out) { |
| 4302 | /* Get boundaries for fan analysis */ |
| 4303 | cbm_cross_pkg_boundary_t *boundaries = NULL; |
| 4304 | int bcount = 0; |
| 4305 | int rc = arch_boundaries(s, project, path, &boundaries, &bcount); |
| 4306 | if (rc != CBM_STORE_OK) { |
| 4307 | return rc; |
| 4308 | } |
| 4309 | |
| 4310 | /* Collect route and entry point packages */ |
| 4311 | char *route_pkgs[CBM_SZ_32]; |
| 4312 | int nrpkgs = |
| 4313 | collect_pkg_names(s, "SELECT qualified_name FROM nodes WHERE project=?1 AND label='Route'", |
| 4314 | project, path, route_pkgs, CBM_SZ_32); |
| 4315 | |
| 4316 | char *entry_pkgs[CBM_SZ_32]; |
| 4317 | int nepkgs = collect_pkg_names(s, |
| 4318 | "SELECT qualified_name FROM nodes WHERE project=?1 AND " |
| 4319 | "json_extract(properties, '$.is_entry_point') = 1", |
| 4320 | project, path, entry_pkgs, CBM_SZ_32); |
| 4321 | |
| 4322 | /* Compute fan-in/out per package */ |
| 4323 | char *all_pkgs[CBM_SZ_64]; |
| 4324 | int fan_in[CBM_SZ_64]; |
| 4325 | int fan_out[CBM_SZ_64]; |
| 4326 | int npkgs = 0; |
| 4327 | memset(fan_in, 0, sizeof(fan_in)); |
| 4328 | memset(fan_out, 0, sizeof(fan_out)); |
| 4329 | |
| 4330 | for (int i = 0; i < bcount; i++) { |
| 4331 | int fi = find_or_add_pkg(all_pkgs, &npkgs, ST_MAX_PKGS, boundaries[i].from); |
| 4332 | if (fi >= 0) { |
| 4333 | fan_out[fi] += boundaries[i].call_count; |
| 4334 | } |
| 4335 | int ti = find_or_add_pkg(all_pkgs, &npkgs, ST_MAX_PKGS, boundaries[i].to); |
| 4336 | if (ti >= 0) { |
| 4337 | fan_in[ti] += boundaries[i].call_count; |
| 4338 | } |
| 4339 | } |
| 4340 | |
| 4341 | /* Also include route/entry packages */ |
| 4342 | for (int i = 0; i < nrpkgs; i++) { |
| 4343 | find_or_add_pkg(all_pkgs, &npkgs, ST_MAX_PKGS, route_pkgs[i]); |
| 4344 | } |
| 4345 | for (int i = 0; i < nepkgs; i++) { |
| 4346 | find_or_add_pkg(all_pkgs, &npkgs, ST_MAX_PKGS, entry_pkgs[i]); |
| 4347 | } |
| 4348 | |
| 4349 | /* Classify each package */ |
| 4350 | out->layers = (npkgs > 0) ? calloc(npkgs, sizeof(cbm_package_layer_t)) : NULL; |
| 4351 | out->layer_count = npkgs; |
| 4352 | for (int i = 0; i < npkgs; i++) { |
| 4353 | bool has_route = pkg_in_list(all_pkgs[i], route_pkgs, nrpkgs); |
| 4354 | bool has_entry = pkg_in_list(all_pkgs[i], entry_pkgs, nepkgs); |
| 4355 | const char *layer; |
| 4356 | const char *reason; |
| 4357 | classify_layer(all_pkgs[i], fan_in[i], fan_out[i], has_route, has_entry, &layer, &reason); |
no test coverage detected