Merge pull request #10 from Oichkatzelesfrettschen/eirikr/build-python-script-to-analyze-file-tree-and-c++23-status
This commit is contained in:
commit
2c1239240e
113
tools/cpp23_enumerate.py
Normal file
113
tools/cpp23_enumerate.py
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Enumerate repository files and guess which are C++23 upgraded.
|
||||
|
||||
The script walks the directory tree rooted at the repository and prints a
|
||||
summary of file types. It also inspects C++ source files and uses simple
|
||||
heuristics to determine whether they likely use C++23 features.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import mimetypes
|
||||
from dataclasses import dataclass
|
||||
from typing import Iterator, List
|
||||
|
||||
|
||||
CXX_EXTENSIONS = {".cpp", ".cc", ".cxx", ".C", ".hpp", ".hh", ".hxx"}
|
||||
|
||||
CXX23_MARKERS = [
|
||||
"consteval", # keyword introduced in C++20, relevant for 23
|
||||
"std::expected", # library feature from C++23
|
||||
"std::print", # print facility in C++23
|
||||
"std::format", # improved in C++23
|
||||
"std::ranges", # ranges library
|
||||
"co_await", # coroutine keyword
|
||||
"#if __cplusplus >= 202302L", # direct version check
|
||||
]
|
||||
|
||||
|
||||
@dataclass
|
||||
class FileInfo:
|
||||
"""Simple container for file information."""
|
||||
|
||||
path: str
|
||||
file_type: str
|
||||
upgraded_cpp23: bool = False
|
||||
|
||||
|
||||
def guess_file_type(path: str) -> str:
|
||||
"""Return a best-effort string describing the file type."""
|
||||
mime, _ = mimetypes.guess_type(path)
|
||||
return mime or "unknown"
|
||||
|
||||
|
||||
def walk_files(root: str) -> Iterator[str]:
|
||||
"""Yield all file paths under *root*."""
|
||||
for current, _, files in os.walk(root):
|
||||
for name in files:
|
||||
yield os.path.join(current, name)
|
||||
|
||||
|
||||
def inspect_file(path: str) -> FileInfo:
|
||||
"""Inspect *path* and return collected information."""
|
||||
ext = os.path.splitext(path)[1]
|
||||
file_type = guess_file_type(path)
|
||||
upgraded = False
|
||||
if ext in CXX_EXTENSIONS:
|
||||
try:
|
||||
with open(path, "r", encoding="utf-8", errors="ignore") as source:
|
||||
data = source.read()
|
||||
except OSError:
|
||||
data = ""
|
||||
upgraded = any(marker in data for marker in CXX23_MARKERS)
|
||||
return FileInfo(path, file_type, upgraded)
|
||||
|
||||
|
||||
def analyze(root: str) -> tuple[list[FileInfo], list[str], list[str]]:
|
||||
"""Analyze the directory tree starting at *root*."""
|
||||
tree: List[FileInfo] = []
|
||||
upgraded: List[str] = []
|
||||
not_upgraded: List[str] = []
|
||||
for path in walk_files(root):
|
||||
info = inspect_file(path)
|
||||
tree.append(info)
|
||||
if os.path.splitext(path)[1] in CXX_EXTENSIONS:
|
||||
(upgraded if info.upgraded_cpp23 else not_upgraded).append(path)
|
||||
return tree, upgraded, not_upgraded
|
||||
|
||||
|
||||
def print_summary(
|
||||
tree: list[FileInfo], upgraded: list[str], not_upgraded: list[str]
|
||||
) -> None:
|
||||
"""Print the collected summary to stdout."""
|
||||
print("File tree and types:\n")
|
||||
for info in tree:
|
||||
print(f"{info.path}: {info.file_type}")
|
||||
print("\nC++23 upgraded files:")
|
||||
for path in upgraded:
|
||||
print(path)
|
||||
print("\nFiles not upgraded to C++23:")
|
||||
for path in not_upgraded:
|
||||
print(path)
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
"""Parse command line arguments."""
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"root", nargs="?", default=".", help="Root directory to scan"
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Entry point for command line execution."""
|
||||
args = parse_args()
|
||||
tree, upgraded, not_upgraded = analyze(args.root)
|
||||
print_summary(tree, upgraded, not_upgraded)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Reference in New Issue
Block a user