Coverage for src / renaissance / project / project_scanner.py: 100%

45 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-09-09 14:04 +0000

1import json 

2from os import system 

3from pathlib import Path 

4 

5 

6class ProjectScanner: 

7 def find_sources(self) -> list[str]: 

8 raise NotImplementedError 

9 

10 

11class CppScanner(ProjectScanner): 

12 def __init__(self, compile_commands_path: str = "compile_commands.json"): 

13 self.compile_commands_path = compile_commands_path 

14 

15 def find_sources(self) -> list[str]: 

16 if not Path(self.compile_commands_path).exists(): 

17 raise FileNotFoundError("compile_commands.json not found") 

18 with Path(self.compile_commands_path).open() as f: 

19 commands = json.load(f) 

20 return sorted(set(entry["file"] for entry in commands if "file" in entry)) 

21 

22 

23class JavaScanner(ProjectScanner): 

24 def __init__(self, root_dir: str = "."): 

25 self.root_dir = root_dir 

26 

27 def find_sources(self) -> list[str]: 

28 java_files = Path(self.root_dir).rglob("*.java") 

29 return sorted(str(f) for f in java_files) 

30 

31 

32class PythonScanner(ProjectScanner): 

33 def __init__(self, root_dir: str = ".", package_dirs: list[str] | None = None): 

34 

35 # return (file_path for file_path in current_dir.iterdir() if is_python_file) 

36 

37 self.root_dir = root_dir 

38 self.package_dirs = package_dirs or ["src", "lib", "test"] 

39 # TODO: Why this hardcoded default heuristic? 

40 # Why not what Python by default enforces or what is derived from the project config? 

41 

42 def find_sources(self) -> list[str]: 

43 files = [] 

44 

45 for d in self.package_dirs: 

46 file_path = Path(self.root_dir) / d 

47 if file_path.exists(): 

48 files.extend(file_path.glob("**/*.py")) 

49 return sorted(files) 

50 

51 

52class BearCppScanner(CppScanner): 

53 def __init__(self, build_dir: str = ".", compile_commands_path: str = "compile_commands.json"): 

54 super().__init__(compile_commands_path) 

55 self.build_dir = build_dir 

56 

57 def run_bear(self): 

58 print("Running Bear to generate compile_commands.json...") 

59 result = system(f"bear -- make -C {self.build_dir}") 

60 if result != 0: 

61 raise RuntimeError("Bear failed to run or make failed.") 

62 

63 def find_sources(self) -> list[str]: 

64 if not Path(self.compile_commands_path).exists(): 

65 self.run_bear() 

66 return super().find_sources()