Init baseline for a project: check if git, get HEAD, count files */
| 1164 | |
| 1165 | /* Init baseline for a project: check if git, get HEAD, count files */ |
| 1166 | static bool init_baseline(cbm_watcher_t *w, project_state_t *s) { |
| 1167 | struct stat st; |
| 1168 | if (stat(s->root_path, &st) != 0) { |
| 1169 | cbm_log_warn("watcher.root_gone", "project", s->project_name, "path", s->root_path); |
| 1170 | s->baseline_done = true; |
| 1171 | s->is_git = false; |
| 1172 | return true; |
| 1173 | } |
| 1174 | |
| 1175 | watcher_git_status_t repository_status = git_repo_status(w, s); |
| 1176 | if (repository_status != WATCHER_GIT_OK && repository_status != WATCHER_GIT_COMMAND_FAILED) { |
| 1177 | return false; |
| 1178 | } |
| 1179 | s->is_git = repository_status == WATCHER_GIT_OK; |
| 1180 | |
| 1181 | /* `rev-parse --git-dir` walks UP, so an ordinary folder that merely happens |
| 1182 | * to live under some unrelated repository answers yes. Treating it as a git |
| 1183 | * project is what produced the runaway churn: it inherits the ancestor's |
| 1184 | * dirty state, which is permanently non-empty and has nothing to do with |
| 1185 | * this directory, so every poll looked like a change. |
| 1186 | * |
| 1187 | * A directory is only really git-managed here if it carries its own .git, |
| 1188 | * or the ancestor repository actually tracks something inside it. A |
| 1189 | * genuine sub-package of a monorepo passes the second test; a scratch or |
| 1190 | * gitignored folder sitting under a repo fails both and is polled as a |
| 1191 | * plain directory instead. */ |
| 1192 | if (s->is_git && !git_has_own_dot_git(s->root_path)) { |
| 1193 | bool tracked = false; |
| 1194 | watcher_git_status_t tracked_status = git_tracks_anything_here(w, s, &tracked); |
| 1195 | if (tracked_status != WATCHER_GIT_OK && tracked_status != WATCHER_GIT_COMMAND_FAILED) { |
| 1196 | return false; |
| 1197 | } |
| 1198 | if (!tracked) { |
| 1199 | s->is_git = false; |
| 1200 | cbm_log_info("watcher.nested_non_git", "project", s->project_name, "path", |
| 1201 | s->root_path); |
| 1202 | } |
| 1203 | } |
| 1204 | |
| 1205 | s->baseline_done = true; |
| 1206 | |
| 1207 | if (s->is_git) { |
| 1208 | watcher_git_status_t cdup_status = git_repo_cdup(w, s, s->repo_cdup, sizeof(s->repo_cdup)); |
| 1209 | if (cdup_status != WATCHER_GIT_OK && cdup_status != WATCHER_GIT_COMMAND_FAILED) { |
| 1210 | s->baseline_done = false; |
| 1211 | return false; |
| 1212 | } |
| 1213 | watcher_git_status_t head_status = git_head(w, s, s->last_head, sizeof(s->last_head)); |
| 1214 | if (head_status != WATCHER_GIT_OK && head_status != WATCHER_GIT_COMMAND_FAILED) { |
| 1215 | s->baseline_done = false; |
| 1216 | return false; |
| 1217 | } |
| 1218 | /* last_dirty_sig stays 0 ("clean known"): a tree that is ALREADY |
| 1219 | * dirty at baseline reindexes once on the first poll — the watcher |
| 1220 | * cannot know whether that state made it into the DB (e.g. server |
| 1221 | * restart with a stale artifact). At-least-once, then the signature |
| 1222 | * gates further polls (#937). */ |
| 1223 | int file_count = 0; |
no test coverage detected