MCPcopy Index your code
hub / github.com/colbymchenry/codegraph / watchTree

Method watchTree

src/sync/watcher.ts:434–498  ·  view source on GitHub ↗

* Add an inotify watch for `dir` and recurse into its non-ignored * subdirectories. When `markExisting` is true (a directory that appeared * AFTER startup), the source files already inside it are recorded as pending * — this closes the `mkdir + write` race where files created before the new

(dir: string, markExisting: boolean)

Source from the content-addressed store, hash-verified

432 * sync owns the baseline).
433 */
434 private watchTree(dir: string, markExisting: boolean): void {
435 // A degrade() mid-walk (exhaustion on an earlier directory) calls stop(),
436 // which sets `stopped`; bail so the recursion unwinds without adding more
437 // watches to a watcher that is shutting down. `inotifyLimitWarned` does the
438 // same after ENOSPC — the kernel budget is gone, so stop trying the rest of
439 // the tree (every add would fail) while keeping the watches already set.
440 if (this.stopped || this.degradedReason || this.inotifyLimitWarned) return;
441 if (this.dirWatchers.has(dir)) return;
442 if (this.dirWatchers.size >= maxDirWatches()) {
443 if (!this.dirCapWarned) {
444 this.dirCapWarned = true;
445 logWarn('File watcher hit directory-watch cap; remaining subtrees rely on manual/periodic sync', {
446 cap: maxDirWatches(),
447 });
448 }
449 return;
450 }
451
452 let w: fs.FSWatcher;
453 try {
454 w = watchImpl(dir, { persistent: true }, (_event, filename) =>
455 this.handleDirEvent(dir, filename)
456 );
457 } catch (err) {
458 // EMFILE/ENFILE means the PROCESS is out of descriptors — every further
459 // directory would fail too, so degrade the whole watcher rather than
460 // limping along with a partial watch set.
461 if (isWatchResourceExhaustion(err)) {
462 this.degrade(EXHAUSTION_REASON, { error: String(err), dir });
463 } else if (isInotifyWatchExhaustion(err)) {
464 // ENOSPC = inotify watch budget exhausted. NON-fatal: keep the watches
465 // we have and tell the user the knob to raise (warn once).
466 this.warnInotifyLimit({ error: String(err), dir });
467 }
468 // ENOENT / EACCES on a single directory stays non-fatal: skip it quietly.
469 return;
470 }
471 w.on('error', (err: unknown) => {
472 if (isWatchResourceExhaustion(err)) {
473 this.degrade(EXHAUSTION_REASON, { error: String(err), dir });
474 return;
475 }
476 if (isInotifyWatchExhaustion(err)) {
477 this.warnInotifyLimit({ error: String(err), dir });
478 }
479 this.unwatchDir(dir);
480 });
481 this.dirWatchers.set(dir, w);
482
483 let entries: fs.Dirent[];
484 try {
485 entries = fs.readdirSync(dir, { withFileTypes: true });
486 } catch {
487 return;
488 }
489 for (const entry of entries) {
490 const child = path.join(dir, entry.name);
491 if (entry.isDirectory()) {

Callers 2

startPerDirectoryMethod · 0.95
handleDirEventMethod · 0.95

Calls 15

handleDirEventMethod · 0.95
degradeMethod · 0.95
warnInotifyLimitMethod · 0.95
unwatchDirMethod · 0.95
shouldIgnoreDirMethod · 0.95
handleChangeMethod · 0.95
logWarnFunction · 0.90
normalizePathFunction · 0.90
maxDirWatchesFunction · 0.85
isInotifyWatchExhaustionFunction · 0.85
hasMethod · 0.80

Tested by

no test coverage detected