From 756dcf017873fc99993fc1df418dcee610d0d7c4 Mon Sep 17 00:00:00 2001 From: Bbowlby22 Date: Fri, 27 Feb 2026 00:41:33 -0600 Subject: [PATCH 1/2] fix(loader): match ignore patterns on repo-relative paths --- fastcode/loader.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/fastcode/loader.py b/fastcode/loader.py index 87977b9..ff9a503 100644 --- a/fastcode/loader.py +++ b/fastcode/loader.py @@ -230,14 +230,27 @@ def scan_files(self) -> List[Dict[str, Any]]: max_file_size_bytes = self.max_file_size_mb * 1024 * 1024 for root, dirs, filenames in os.walk(self.repo_path): - # Filter out ignored directories - dirs[:] = [d for d in dirs if not should_ignore_path( - os.path.join(root, d), effective_ignore - )] + # Filter ignored directories using repo-relative paths so gitwildmatch + # patterns like "output/" or ".venv/" match consistently. + filtered_dirs = [] + for d in dirs: + abs_dir_path = os.path.join(root, d) + rel_dir_path = normalize_path( + os.path.relpath(abs_dir_path, self.repo_path) + ) + rel_dir_with_trailing = f"{rel_dir_path}/" + if should_ignore_path( + rel_dir_path, effective_ignore + ) or should_ignore_path(rel_dir_with_trailing, effective_ignore): + continue + filtered_dirs.append(d) + dirs[:] = filtered_dirs for filename in filenames: file_path = os.path.join(root, filename) - relative_path = os.path.relpath(file_path, self.repo_path) + relative_path = normalize_path( + os.path.relpath(file_path, self.repo_path) + ) # Check if should ignore if should_ignore_path(relative_path, effective_ignore): @@ -347,4 +360,3 @@ def cleanup(self): def __del__(self): """Cleanup on deletion""" self.cleanup() - From 860eed173dd117008b58d981be87e5a9c67f55b7 Mon Sep 17 00:00:00 2001 From: Bbowlby22 Date: Sat, 28 Feb 2026 22:43:05 -0600 Subject: [PATCH 2/2] perf(loader): precompile ignore matcher during repository scan --- fastcode/loader.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/fastcode/loader.py b/fastcode/loader.py index ff9a503..6d2272e 100644 --- a/fastcode/loader.py +++ b/fastcode/loader.py @@ -10,10 +10,11 @@ from typing import Dict, List, Optional, Any import logging from git import Repo, GitCommandError +from pathspec import PathSpec +from pathspec.patterns import GitWildMatchPattern from .utils import ( is_supported_file, - should_ignore_path, get_repo_name_from_url, normalize_path, ensure_dir, @@ -228,7 +229,19 @@ def scan_files(self) -> List[Dict[str, Any]]: files = [] total_size = 0 max_file_size_bytes = self.max_file_size_mb * 1024 * 1024 - + ignore_spec = PathSpec.from_lines(GitWildMatchPattern, effective_ignore) + + def is_ignored_repo_relative(rel_path: str, *, is_dir: bool = False) -> bool: + """Match ignore patterns against normalized repo-relative paths.""" + normalized = normalize_path(rel_path) + if ignore_spec.match_file(normalized): + return True + # Directory-style patterns (e.g. "output/" or ".venv/") are most + # reliable with a trailing slash candidate. + if is_dir and ignore_spec.match_file(f"{normalized}/"): + return True + return False + for root, dirs, filenames in os.walk(self.repo_path): # Filter ignored directories using repo-relative paths so gitwildmatch # patterns like "output/" or ".venv/" match consistently. @@ -238,22 +251,17 @@ def scan_files(self) -> List[Dict[str, Any]]: rel_dir_path = normalize_path( os.path.relpath(abs_dir_path, self.repo_path) ) - rel_dir_with_trailing = f"{rel_dir_path}/" - if should_ignore_path( - rel_dir_path, effective_ignore - ) or should_ignore_path(rel_dir_with_trailing, effective_ignore): + if is_ignored_repo_relative(rel_dir_path, is_dir=True): continue filtered_dirs.append(d) dirs[:] = filtered_dirs for filename in filenames: file_path = os.path.join(root, filename) - relative_path = normalize_path( - os.path.relpath(file_path, self.repo_path) - ) + relative_path = normalize_path(os.path.relpath(file_path, self.repo_path)) # Check if should ignore - if should_ignore_path(relative_path, effective_ignore): + if is_ignored_repo_relative(relative_path): continue # Check if supported extension