Resolve merge conflict with main (gitignore + symlink rename)
Keeps the PR's visitedDirs rename and main's gitIgnoredDirs addition.
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { CodeGraphConfig, DEFAULT_CONFIG, Language, NodeKind } from './types';
|
||||
import { normalizePath } from './utils';
|
||||
|
||||
/**
|
||||
* Configuration filename
|
||||
@@ -240,6 +241,9 @@ export function addCustomPattern(
|
||||
* Check if a file path matches the include/exclude patterns
|
||||
*/
|
||||
export function shouldIncludeFile(filePath: string, config: CodeGraphConfig): boolean {
|
||||
// Normalize to forward slashes so Windows backslash paths match glob patterns
|
||||
filePath = normalizePath(filePath);
|
||||
|
||||
// Simple glob matching (for now, just check if any pattern matches)
|
||||
// A full implementation would use a proper glob library
|
||||
|
||||
|
||||
+40
-2
@@ -8,6 +8,7 @@ import * as fs from 'fs';
|
||||
import * as fsp from 'fs/promises';
|
||||
import * as path from 'path';
|
||||
import * as crypto from 'crypto';
|
||||
import { execFileSync } from 'child_process';
|
||||
import {
|
||||
Language,
|
||||
FileRecord,
|
||||
@@ -20,7 +21,7 @@ import { extractFromSource } from './tree-sitter';
|
||||
import { detectLanguage, isLanguageSupported } from './grammars';
|
||||
import { logDebug, logWarn } from '../errors';
|
||||
import { captureException } from '../sentry';
|
||||
import { validatePathWithinRoot } from '../utils';
|
||||
import { validatePathWithinRoot, normalizePath } from '../utils';
|
||||
|
||||
/**
|
||||
* Number of files to read in parallel during indexing.
|
||||
@@ -74,6 +75,9 @@ export function hashContent(content: string): string {
|
||||
* Check if a path matches any glob pattern (simplified)
|
||||
*/
|
||||
function matchesGlob(filePath: string, pattern: string): boolean {
|
||||
// Normalize to forward slashes so Windows backslash paths match glob patterns
|
||||
filePath = normalizePath(filePath);
|
||||
|
||||
// Convert glob to regex using placeholders to avoid conflicts
|
||||
let regexStr = pattern;
|
||||
|
||||
@@ -120,6 +124,31 @@ export function shouldIncludeFile(
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get directories ignored by .gitignore using git ls-files.
|
||||
* Returns a Set of normalized relative directory paths (forward slashes, no trailing slash).
|
||||
* Gracefully returns empty Set on any failure.
|
||||
*/
|
||||
function getGitIgnoredDirectories(rootDir: string): Set<string> {
|
||||
try {
|
||||
const output = execFileSync(
|
||||
'git',
|
||||
['ls-files', '-oi', '--exclude-standard', '--directory'],
|
||||
{ cwd: rootDir, encoding: 'utf-8', timeout: 10000, stdio: ['pipe', 'pipe', 'pipe'] }
|
||||
);
|
||||
const dirs = new Set<string>();
|
||||
for (const line of output.split('\n')) {
|
||||
const trimmed = line.trim();
|
||||
if (trimmed.endsWith('/')) {
|
||||
dirs.add(normalizePath(trimmed.slice(0, -1)));
|
||||
}
|
||||
}
|
||||
return dirs;
|
||||
} catch {
|
||||
return new Set<string>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marker file name that indicates a directory (and all children) should be skipped
|
||||
*/
|
||||
@@ -137,6 +166,7 @@ export function scanDirectory(
|
||||
let count = 0;
|
||||
// Track visited real paths to detect symlink cycles
|
||||
const visitedDirs = new Set<string>();
|
||||
const gitIgnoredDirs = getGitIgnoredDirectories(rootDir);
|
||||
|
||||
function walk(dir: string): void {
|
||||
// Resolve real path to detect symlink cycles
|
||||
@@ -172,7 +202,7 @@ export function scanDirectory(
|
||||
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
const relativePath = path.relative(rootDir, fullPath);
|
||||
const relativePath = normalizePath(path.relative(rootDir, fullPath));
|
||||
|
||||
// Follow symlinked directories, but skip symlinked files to non-project targets
|
||||
if (entry.isSymbolicLink()) {
|
||||
@@ -180,6 +210,10 @@ export function scanDirectory(
|
||||
const realTarget = fs.realpathSync(fullPath);
|
||||
const stat = fs.statSync(realTarget);
|
||||
if (stat.isDirectory()) {
|
||||
// Check gitignore first (fast O(1) lookup)
|
||||
if (gitIgnoredDirs.has(relativePath)) {
|
||||
continue;
|
||||
}
|
||||
// Check exclusion, then recurse (cycle detection handles the rest)
|
||||
const dirPattern = relativePath + '/';
|
||||
let excluded = false;
|
||||
@@ -208,6 +242,10 @@ export function scanDirectory(
|
||||
}
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
// Check gitignore first (fast O(1) lookup)
|
||||
if (gitIgnoredDirs.has(relativePath)) {
|
||||
continue;
|
||||
}
|
||||
// Check if directory should be excluded
|
||||
const dirPattern = relativePath + '/';
|
||||
let excluded = false;
|
||||
|
||||
@@ -74,6 +74,14 @@ export function clamp(value: number, min: number, max: number): number {
|
||||
return Math.max(min, Math.min(max, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a file path to use forward slashes.
|
||||
* Fixes Windows backslash paths so glob matching works consistently.
|
||||
*/
|
||||
export function normalizePath(filePath: string): string {
|
||||
return filePath.replace(/\\/g, '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Cross-process file lock using lock files.
|
||||
* Prevents concurrent database writes from CLI, MCP server, and git hooks.
|
||||
|
||||
Reference in New Issue
Block a user