| 3333 | } |
| 3334 | |
| 3335 | static int application_background_index(cbm_daemon_application_t *application, |
| 3336 | const char *project_name, const char *root_path, |
| 3337 | bool require_live_watch) { |
| 3338 | if (!application || !project_name || !root_path) { |
| 3339 | return -1; |
| 3340 | } |
| 3341 | char canonical_root[APPLICATION_PATH_CAP]; |
| 3342 | struct stat root_status; |
| 3343 | if (!cbm_canonical_path(root_path, canonical_root, sizeof(canonical_root)) || |
| 3344 | stat(canonical_root, &root_status) != 0 || !S_ISDIR(root_status.st_mode)) { |
| 3345 | return -1; |
| 3346 | } |
| 3347 | yyjson_mut_doc *document = yyjson_mut_doc_new(NULL); |
| 3348 | yyjson_mut_val *root = document ? yyjson_mut_obj(document) : NULL; |
| 3349 | if (!document || !root) { |
| 3350 | yyjson_mut_doc_free(document); |
| 3351 | return -1; |
| 3352 | } |
| 3353 | yyjson_mut_doc_set_root(document, root); |
| 3354 | bool encoded = yyjson_mut_obj_add_strcpy(document, root, "repo_path", canonical_root); |
| 3355 | char *default_project = cbm_project_name_from_path(canonical_root); |
| 3356 | bool custom_project = |
| 3357 | project_name[0] && (!default_project || strcmp(default_project, project_name) != 0); |
| 3358 | if (encoded && custom_project) { |
| 3359 | encoded = yyjson_mut_obj_add_strcpy(document, root, "name", project_name); |
| 3360 | } |
| 3361 | free(default_project); |
| 3362 | char *args = encoded ? yyjson_mut_write(document, 0, NULL) : NULL; |
| 3363 | yyjson_mut_doc_free(document); |
| 3364 | if (!args) { |
| 3365 | return -1; |
| 3366 | } |
| 3367 | char *project_key = application_index_project_key(canonical_root, args); |
| 3368 | if (!project_key) { |
| 3369 | free(args); |
| 3370 | return -1; |
| 3371 | } |
| 3372 | |
| 3373 | application_job_subscribe_status_t subscribe_status = APPLICATION_JOB_SUBSCRIBE_UNAVAILABLE; |
| 3374 | application_jobs_reap_completed(application); |
| 3375 | cbm_mutex_lock(&application->mutex); |
| 3376 | cbm_daemon_application_watch_t *watch = |
| 3377 | require_live_watch ? application_find_watch_locked(application, project_name) : NULL; |
| 3378 | bool watch_live = !require_live_watch || |
| 3379 | (watch && watch->subscribers > 0 && strcmp(watch->root, canonical_root) == 0); |
| 3380 | size_t watch_owner_count = 0; |
| 3381 | bool watch_subscriptions_ok = true; |
| 3382 | cbm_daemon_application_job_t *job = |
| 3383 | watch_live ? application_job_subscribe_locked(application, project_key, canonical_root, |
| 3384 | args, &subscribe_status) |
| 3385 | : NULL; |
| 3386 | if (job && require_live_watch) { |
| 3387 | watch_subscriptions_ok = application_watch_job_subscribe_sessions_locked( |
| 3388 | application, watch, job, &watch_owner_count); |
| 3389 | if (watch_subscriptions_ok && watch_owner_count > 0) { |
| 3390 | job->watcher_waiters++; |
| 3391 | } else if (!watch_subscriptions_ok) { |
| 3392 | subscribe_status = APPLICATION_JOB_SUBSCRIBE_ALLOCATION_FAILED; |
no test coverage detected