Skip to content

Commit

Permalink
feat: ✨ Use pathspec everywhere
Browse files Browse the repository at this point in the history
  • Loading branch information
robvanderleek committed Dec 7, 2024
1 parent 79997a3 commit 103c86f
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 50 deletions.
51 changes: 19 additions & 32 deletions codelimit/common/Scanner.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import fnmatch
import locale
import os
from datetime import datetime
Expand Down Expand Up @@ -41,7 +40,6 @@ def scan_codebase(path: Path, cached_report: Union[Report, None] = None) -> Code
print_header(cached_report, path)
scan_totals = ScanTotals()
with Live(refresh_per_second=2) as live:

def add_file_entry(entry: SourceFileEntry):
scan_totals.add(entry)
table = ScanResultTable(scan_totals)
Expand Down Expand Up @@ -81,20 +79,22 @@ def print_refactor_candidates(scan_totals: ScanTotals):


def _scan_folder(
codebase: Codebase,
folder: Path,
cached_report: Union[Report, None] = None,
add_file_entry: Union[Callable[[SourceFileEntry], None], None] = None,
codebase: Codebase,
folder: Path,
cached_report: Union[Report, None] = None,
add_file_entry: Union[Callable[[SourceFileEntry], None], None] = None,
):
gitignore = _read_gitignore(folder)
excludes = Configuration.excludes.copy()
gitignore_excludes = _read_gitignore(folder)
if gitignore_excludes:
excludes.extend(gitignore_excludes)
excludes_spec = PathSpec.from_lines("gitignore", excludes)
for root, dirs, files in os.walk(folder.absolute()):
files = [f for f in files if not f[0] == "."]
dirs[:] = [d for d in dirs if not d[0] == "."]
for file in files:
rel_path = Path(os.path.join(root, file)).relative_to(folder.absolute())
if is_excluded(rel_path) or (
gitignore is not None and is_excluded_by_gitignore(rel_path, gitignore)
):
if is_excluded(rel_path, excludes_spec):
continue
try:
lexer = get_lexer_for_filename(rel_path)
Expand All @@ -112,11 +112,11 @@ def _scan_folder(


def _scan_file(
codebase: Codebase,
lexer: Lexer,
root: Path,
path: str,
cached_report: Union[Report, None] = None,
codebase: Codebase,
lexer: Lexer,
root: Path,
path: str,
cached_report: Union[Report, None] = None,
) -> SourceFileEntry:
checksum = calculate_checksum(path)
rel_path = relpath(path, root)
Expand Down Expand Up @@ -178,25 +178,12 @@ def scan_file(tokens: list[Token], language: Language) -> list[Measurement]:
return measurements


def is_excluded(path: Path):
for exclude in Configuration.excludes:
exclude_parts = exclude.split(os.sep)
if len(exclude_parts) == 1:
for part in path.parts:
if fnmatch.fnmatch(part, exclude):
return True
else:
if fnmatch.fnmatch(str(path), exclude):
return True
return False


def _read_gitignore(path: Path) -> PathSpec | None:
def _read_gitignore(path: Path) -> list[str] | None:
gitignore_path = path.joinpath(".gitignore")
if gitignore_path.exists():
return PathSpec.from_lines("gitignore", gitignore_path.read_text().splitlines())
return gitignore_path.read_text().splitlines()
return None


def is_excluded_by_gitignore(path: Path, gitignore: PathSpec):
return gitignore.match_file(path)
def is_excluded(path: Path, spec: PathSpec):
return spec.match_file(path)
34 changes: 16 additions & 18 deletions tests/common/test_Scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
from codelimit.common.Configuration import Configuration
from codelimit.common.Scanner import (
scan_codebase,
is_excluded,
is_excluded_by_gitignore,
is_excluded
)
from codelimit.common.source_utils import get_location_range

Expand Down Expand Up @@ -88,30 +87,29 @@ def test_skip_hidden_files():


def test_is_excluded():
assert is_excluded(Path("venv/foo/bar.py"))
assert not is_excluded(Path("foo/bar.py"))
excludes_spec = PathSpec.from_lines("gitignore", Configuration.excludes)

Configuration.excludes = ["output"]
assert is_excluded(Path("venv/foo/bar.py"), excludes_spec)
assert not is_excluded(Path("foo/bar.py"), excludes_spec)

assert is_excluded(Path("output/foo/bar.py"))
assert not is_excluded(Path("venv/foo/bar.py"))
assert not is_excluded(Path("foo/bar.py"))
excludes_spec = PathSpec.from_lines("gitignore", ["output"])

Configuration.excludes = ["foo/bar/*"]
assert is_excluded(Path("output/foo/bar.py"), excludes_spec)
assert not is_excluded(Path("venv/foo/bar.py"), excludes_spec)
assert not is_excluded(Path("foo/bar.py"), excludes_spec)

assert is_excluded(Path("foo/bar/foobar.py"))
excludes_spec = PathSpec.from_lines("gitignore", ["foo/bar/*"])

assert is_excluded(Path("foo/bar/foobar.py"), excludes_spec)

def test_is_excluded_by_gitignore():
Configuration.excludes = ["site/"]
gitignore = PathSpec.from_lines("gitwildmatch", ["site/"])
excludes_spec = PathSpec.from_lines("gitignore", ["site/"])

assert is_excluded_by_gitignore(
Path("site/assets/javascripts/lunr/wordcut.js"), gitignore
assert is_excluded(
Path("site/assets/javascripts/lunr/wordcut.js"), excludes_spec
)

gitignore = PathSpec.from_lines("gitwildmatch", ["!site/"])
excludes_spec = PathSpec.from_lines("gitignore", ["!site/"])

assert not is_excluded_by_gitignore(
Path("site/assets/javascripts/lunr/wordcut.js"), gitignore
assert not is_excluded(
Path("site/assets/javascripts/lunr/wordcut.js"), excludes_spec
)

0 comments on commit 103c86f

Please sign in to comment.