PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
 
Loading...
Searching...
No Matches
repo_files.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2"""One git-backed enumeration of the repository's reviewable files.
3
4Every documentation scanner needs the same set: files this commit carries, plus
5non-ignored untracked ones, minus generated scratch. Four scanners each had their own
6copy, and every copy shared one defect - `git ls-files` reports a path the index still
7tracks even after the worktree file is deleted, so a scanner would enumerate it and
8then fail on `read_text()`. Deleting a page is ordinary work, and the constituent
9audits must keep running against a dirty tree even though `certify-docs` refuses one.
10"""
11
12from __future__ import annotations
13
14import subprocess
15from pathlib import Path
16
17
18def enumerate_repository_files(repo_root: Path, suffix: str = "",
19 skip_dirs: frozenset = frozenset()) -> list:
20 """!
21 @brief List tracked plus non-ignored untracked files that exist on disk.
22
23 @details Paths the index tracks but the worktree no longer holds are filtered out:
24 a deletion staged or unstaged is still a deletion, and reading it would
25 raise rather than report a finding.
26 @param[in] repo_root Repository root directory.
27 @param[in] suffix Restrict to paths with this suffix, or empty for all files.
28 @param[in] skip_dirs Path components whose presence excludes a file.
29 @return Sorted existing paths, or None when git enumeration is unavailable.
30 """
31 entries: list = []
32 for args in (["ls-files", "-z"], ["ls-files", "-z", "--others", "--exclude-standard"]):
33 result = subprocess.run(
34 ["git", "-C", str(repo_root), *args], capture_output=True, text=True, check=False
35 )
36 if result.returncode != 0:
37 return None
38 entries.extend(
39 entry for entry in result.stdout.split("\0")
40 if entry and (not suffix or entry.endswith(suffix))
41 )
42 return sorted({
43 repo_root / entry for entry in entries
44 if not skip_dirs.intersection(Path(entry).parts)
45 and (repo_root / entry).is_file()
46 })