MCPcopy
hub / github.com/colbymchenry/codegraph / discoverEmbeddedRepoRoots

Function discoverEmbeddedRepoRoots

src/extraction/index.ts:557–613  ·  view source on GitHub ↗
(rootDir: string)

Source from the content-addressed store, hash-verified

555 * there already.
556 */
557export function discoverEmbeddedRepoRoots(rootDir: string): string[] {
558 try {
559 execFileSync('git', ['rev-parse', '--git-dir'], { cwd: rootDir, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true });
560 } catch {
561 return [];
562 }
563 const out: string[] = [];
564 const defaults = defaultsOnlyIgnore();
565 const includeIgnored = loadIncludeIgnoredMatcher(rootDir);
566 const visit = (repoAbs: string, prefix: string): void => {
567 const candidates: string[] = [];
568 try {
569 const o = execFileSync(
570 'git',
571 ['ls-files', '-z', '-o', '--exclude-standard', '--directory'],
572 { cwd: repoAbs, encoding: 'utf-8', timeout: 30000, maxBuffer: 50 * 1024 * 1024, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true }
573 );
574 for (const e of o.split('\0')) {
575 if (e.endsWith('/') && !isWholeCwdEntry(e) && !defaults.ignores(e)) {
576 candidates.push(...findNestedGitRepos(path.join(repoAbs, e), e));
577 }
578 }
579 } catch { /* untracked listing failed — ignored-side discovery still runs */ }
580 // Unexpanded gitlinks (mode 160000) with a real checkout on disk — embedded
581 // repos `git add`ed without `.gitmodules`, or submodules not active here. The
582 // untracked listing above can't see them (they're tracked), so find them the
583 // same way collectGitFiles does, keeping watcher scope == indexer scope.
584 // (#1031, #1033)
585 try {
586 const staged = execFileSync(
587 'git',
588 ['ls-files', '-z', '-s', '--recurse-submodules'],
589 { cwd: repoAbs, encoding: 'utf-8', timeout: 30000, maxBuffer: 50 * 1024 * 1024, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true }
590 );
591 const repoIgnore = buildDefaultIgnore(repoAbs);
592 for (const entry of staged.split('\0')) {
593 if (!entry || entry.slice(0, 6) !== '160000') continue;
594 const tab = entry.indexOf('\t');
595 if (tab === -1) continue;
596 const rel = entry.slice(tab + 1);
597 const relDir = rel.endsWith('/') ? rel : rel + '/';
598 // A gitlink under a gitignored path is respected (not indexed) unless the
599 // project opted it in — same rule as the untracked-ignored kind (#1065).
600 if (gitlinkEmbeddedRepoSkipped(relDir, prefix, defaults, repoIgnore, includeIgnored)) continue;
601 if (classifyGitDir(path.join(repoAbs, rel)) === 'embedded') candidates.push(relDir);
602 }
603 } catch { /* staged listing failed — other discovery still runs */ }
604 candidates.push(...findIgnoredEmbeddedRepos(repoAbs, includeIgnored, prefix));
605 for (const rel of candidates) {
606 const full = normalizePath(prefix + rel);
607 out.push(full);
608 visit(path.join(repoAbs, rel), full);
609 }
610 };
611 visit(rootDir, '');
612 return out;
613}
614

Callers 3

extraction.test.tsFile · 0.90
buildScopeIgnoreFunction · 0.85

Calls 3

defaultsOnlyIgnoreFunction · 0.85
visitFunction · 0.85

Tested by

no test coverage detected