Last active
          August 28, 2025 16:09 
        
      - 
      
 - 
        
Save xtqqczze/5f660920a6587e9436b676ed90efdede to your computer and use it in GitHub Desktop.  
    This file was generated by ChatGPT on 2025-08-28
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | #!/usr/bin/env python3 | |
| """ | |
| find_unreferenced_cs.py | |
| Finds all *.cs files under a given directory and lists the ones | |
| whose **filename** is not mentioned in ANY *.csproj or *.projitems in the repo. | |
| Run from repo root: | |
| python3 find_unreferenced_cs.py --dir src/libraries/Common/src/Interop | |
| Options: | |
| --repo-root . # default: current directory | |
| --dir <path> # directory to scan for .cs files (relative to repo root) | |
| --ignore-case # do case-insensitive matching (default is case-sensitive) | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import sys | |
| from pathlib import Path | |
| def read_text_best_effort(p: Path) -> str: | |
| """Read text from a file with best-effort encoding fallback.""" | |
| for enc in ("utf-8", "utf-16-le", "utf-16-be", "latin-1"): | |
| try: | |
| return p.read_text(encoding=enc) | |
| except Exception: | |
| pass | |
| return p.read_bytes().decode("utf-8", errors="ignore") | |
| def main() -> None: | |
| ap = argparse.ArgumentParser(description="List .cs files not mentioned in any project file.") | |
| ap.add_argument("--repo-root", default=".", help="Path to repo root (default: .)") | |
| ap.add_argument("--dir", required=True, | |
| help="Path (relative to repo root) of directory to scan for .cs files.") | |
| ap.add_argument("--ignore-case", action="store_true", | |
| help="Use case-insensitive matching (default: case-sensitive).") | |
| args = ap.parse_args() | |
| root = Path(args.repo_root).resolve() | |
| target_dir = (root / args.dir).resolve() | |
| if not target_dir.exists(): | |
| print(f"ERROR: Target directory not found: {target_dir}", file=sys.stderr) | |
| sys.exit(2) | |
| # Gather all project files in repo | |
| proj_files = list(root.rglob("*.csproj")) + list(root.rglob("*.projitems")) | |
| if not proj_files: | |
| print("WARNING: No .csproj or .projitems files found in repo.", file=sys.stderr) | |
| # Read all project files into one big string for fast membership checks | |
| chunks = [] | |
| for pf in proj_files: | |
| try: | |
| chunks.append(read_text_best_effort(pf)) | |
| except Exception as e: | |
| print(f"WARNING: Could not read {pf}: {e}", file=sys.stderr) | |
| haystack = "\n".join(chunks) | |
| haystack_cmp = haystack if not args.ignore_case else haystack.lower() | |
| # Find all .cs files under target_dir | |
| cs_files = sorted(target_dir.rglob("*.cs")) | |
| unreferenced: list[str] = [] | |
| for cf in cs_files: | |
| name = cf.name | |
| key = name if not args.ignore_case else name.lower() | |
| if key not in haystack_cmp: | |
| unreferenced.append(str(cf.relative_to(root))) | |
| # Print results | |
| for path in unreferenced: | |
| print(path) | |
| print( | |
| f"\n# Summary: {len(unreferenced)} of {len(cs_files)} .cs files in {target_dir.relative_to(root)} " | |
| f"not mentioned in any .csproj/.projitems", | |
| file=sys.stderr | |
| ) | |
| if __name__ == "__main__": | |
| main() | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment