From e55f4013bc0623d8f964072f765ac1c9dabfebe6 Mon Sep 17 00:00:00 2001 From: shixi-li Date: Sat, 25 Jul 2026 01:26:46 +0800 Subject: [PATCH] fix: preserve inverted gitignore traversal --- pyproject.toml | 2 +- tests/test_file_walk.py | 41 +++++++++++++++++++++++++++++++++++++++++ uv.lock | 8 ++++---- 3 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 tests/test_file_walk.py diff --git a/pyproject.toml b/pyproject.toml index b8858bb..7e3bb6d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,7 @@ dependencies = [ "einops>=0.8.2", "typer>=0.9.0", "msgspec>=0.19.0", - "pathspec>=0.12.1", + "pathspec>=0.12.1,<1.0", "pyyaml>=6.0", "questionary>=2.0.0", ] diff --git a/tests/test_file_walk.py b/tests/test_file_walk.py new file mode 100644 index 0000000..0859a07 --- /dev/null +++ b/tests/test_file_walk.py @@ -0,0 +1,41 @@ +"""Tests for shared source-file walking and gitignore filtering.""" + +from pathlib import Path + +from cocoindex_code.file_walk import build_matcher, iter_included_files + + +def test_inverted_gitignore_keeps_source_directories_traversable(tmp_path: Path) -> None: + """An ignore-all file can reopen directories and selected source extensions.""" + (tmp_path / ".gitignore").write_text( + "\n".join( + [ + "*", + "!*/", + "!*.cpp", + "!*.h", + "Content/", + "", + ] + ) + ) + + files = { + "Root.cpp": "int root;\n", + "Engine/Source/kept.cpp": "int kept;\n", + "Engine/Source/kept.h": "#pragma once\n", + "Engine/Source/ignored.bin": "generated\n", + "Content/reignored.cpp": "int generated;\n", + } + for relative_path, contents in files.items(): + path = tmp_path / relative_path + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(contents) + + matcher = build_matcher(tmp_path, ["**/*.cpp", "**/*.h"], []) + included = { + relative_path.as_posix() + for _, relative_path in iter_included_files(tmp_path, tmp_path, matcher) + } + + assert included == {"Root.cpp", "Engine/Source/kept.cpp", "Engine/Source/kept.h"} diff --git a/uv.lock b/uv.lock index f6946d8..c92f9e3 100644 --- a/uv.lock +++ b/uv.lock @@ -445,7 +445,7 @@ requires-dist = [ { name = "msgspec", specifier = ">=0.19.0" }, { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.0.0" }, { name = "numpy", specifier = ">=1.24.0" }, - { name = "pathspec", specifier = ">=0.12.1" }, + { name = "pathspec", specifier = ">=0.12.1,<1.0" }, { name = "prek", marker = "extra == 'dev'", specifier = ">=0.1.0" }, { name = "pydantic", specifier = ">=2.0.0" }, { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.0.0" }, @@ -1852,11 +1852,11 @@ wheels = [ [[package]] name = "pathspec" -version = "1.0.4" +version = "0.12.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fa/36/e27608899f9b8d4dff0617b2d9ab17ca5608956ca44461ac14ac48b44015/pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645", size = 131200, upload-time = "2026-01-27T03:59:46.938Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" }, + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, ] [[package]]