2222import re
2323import shlex
2424import subprocess
25- import sys
2625import tempfile
2726from collections import defaultdict
2827from concurrent .futures import ProcessPoolExecutor , as_completed
29- from pathlib import Path
30- from typing import Dict , List , Optional , Set , Tuple
28+ from typing import Dict , List , Optional , Set
3129
3230
3331class CompileCommandsParser :
@@ -55,7 +53,9 @@ def parse(self, extensions: Optional[List[str]] = None) -> List[Dict]:
5553 json.JSONDecodeError: If file contains invalid JSON
5654 """
5755 if not os .path .exists (self .compile_commands_path ):
58- raise FileNotFoundError (f"compile_commands.json not found: { self .compile_commands_path } " )
56+ raise FileNotFoundError (
57+ f"compile_commands.json not found: { self .compile_commands_path } "
58+ )
5959
6060 with open (self .compile_commands_path , "r" ) as f :
6161 commands = json .load (f )
@@ -92,7 +92,9 @@ def __init__(self, parallel_workers: int = 1, timeout: int = 30):
9292 self .timeout = timeout
9393 self ._temp_dir = None
9494
95- def convert_to_dependency_command (self , compile_command : str , deps_output_file : str ) -> List [str ]:
95+ def convert_to_dependency_command (
96+ self , compile_command : str , deps_output_file : str
97+ ) -> List [str ]:
9698 """Convert a compile command to a dependency extraction command.
9799
98100 Replaces -c with -MM and removes -o output specification.
@@ -158,7 +160,7 @@ def parse_makefile_deps(self, deps_content: str) -> List[str]:
158160 return []
159161
160162 # Everything after the colon is dependencies
161- deps_part = content [colon_pos + 1 :]
163+ deps_part = content [colon_pos + 1 :]
162164
163165 # Split on whitespace and filter empty strings
164166 deps = [d .strip () for d in deps_part .split () if d .strip ()]
@@ -180,7 +182,9 @@ def _get_deps_file(self, source_file: str) -> str:
180182 basename = os .path .basename (source_file )
181183 return os .path .join (self ._temp_dir , f"{ basename } .d" )
182184
183- def extract (self , directory : str , compile_command : str , source_file : str ) -> List [str ]:
185+ def extract (
186+ self , directory : str , compile_command : str , source_file : str
187+ ) -> List [str ]:
184188 """Extract dependencies for a single source file.
185189
186190 Args:
@@ -203,7 +207,7 @@ def extract(self, directory: str, compile_command: str, source_file: str) -> Lis
203207 cwd = directory ,
204208 capture_output = True ,
205209 text = True ,
206- errors = ' replace' ,
210+ errors = " replace" ,
207211 timeout = self .timeout ,
208212 )
209213
@@ -212,7 +216,7 @@ def extract(self, directory: str, compile_command: str, source_file: str) -> Lis
212216
213217 # Parse the generated .d file
214218 if os .path .exists (deps_file ):
215- with open (deps_file , "r" , errors = ' replace' ) as f :
219+ with open (deps_file , "r" , errors = " replace" ) as f :
216220 deps_content = f .read ()
217221 return self .parse_makefile_deps (deps_content )
218222
@@ -335,7 +339,9 @@ def parse_object_to_source(self) -> Dict[str, str]:
335339
336340 # Pattern to match object compilation rules
337341 # Example: build test/test.cpp.o: CXX_COMPILER__target /src/test.cpp
338- obj_pattern = re .compile (r"^build\s+([^:]+\.(?:cpp|cc|cu|hip)\.o):\s+\S+\s+(\S+)" )
342+ obj_pattern = re .compile (
343+ r"^build\s+([^:]+\.(?:cpp|cc|cu|hip)\.o):\s+\S+\s+(\S+)"
344+ )
339345
340346 with open (self .ninja_file_path , "r" ) as f :
341347 for line in f :
@@ -371,7 +377,7 @@ def normalize_path(self, path: str) -> str:
371377 Normalized relative path
372378 """
373379 if self .workspace_root and path .startswith (self .workspace_root ):
374- return path [len (self .workspace_root ):]
380+ return path [len (self .workspace_root ) :]
375381 return path
376382
377383 def is_project_file (self , file_path : str ) -> bool :
@@ -567,7 +573,9 @@ def analyze(self, progress_callback=None):
567573 """
568574 # Validate required paths
569575 if self .compile_commands_path is None :
570- raise ValueError ("compile_commands_path is required for analysis but was None" )
576+ raise ValueError (
577+ "compile_commands_path is required for analysis but was None"
578+ )
571579 if self .ninja_path is None :
572580 raise ValueError ("ninja_path is required for analysis but was None" )
573581
@@ -588,7 +596,9 @@ def dep_progress(current, total):
588596 if progress_callback :
589597 progress_callback ("extracting_dependencies" , current , total )
590598
591- source_to_deps = extractor .extract_batch (commands , progress_callback = dep_progress )
599+ source_to_deps = extractor .extract_batch (
600+ commands , progress_callback = dep_progress
601+ )
592602
593603 # Phase 3: Parse ninja target mappings
594604 if progress_callback :
@@ -707,10 +717,8 @@ def main():
707717 args = parser .parse_args ()
708718
709719 def progress (phase , current , total ):
710- if not args .quiet :
711- print (f"[{ phase } ] { current } /{ total } " , end = "\r " )
712- if current == total :
713- print ()
720+ if not args .quiet and current == total :
721+ print (f"[{ phase } ] { current } /{ total } " )
714722
715723 analyzer = CMakeDependencyAnalyzer (
716724 compile_commands_path = args .compile_commands ,
@@ -721,12 +729,12 @@ def progress(phase, current, total):
721729
722730 # Check if cache needs regeneration
723731 if not args .force and not analyzer .should_regenerate_cache (args .output ):
724- print (f "Cache is valid, skipping analysis. Use --force to regenerate." )
732+ print ("Cache is valid, skipping analysis. Use --force to regenerate." )
725733 print (f"Using cached results from { args .output } " )
726734 return
727735
728736 if not args .force and os .path .exists (args .output ):
729- print (f "Cache invalid or outdated, regenerating dependencies..." )
737+ print ("Cache invalid or outdated, regenerating dependencies..." )
730738
731739 print (f"Analyzing dependencies from { args .compile_commands } ..." )
732740 analyzer .analyze (progress_callback = progress )
@@ -735,10 +743,12 @@ def progress(phase, current, total):
735743 analyzer .export_to_json (args .output )
736744
737745 stats = analyzer .calculate_statistics ()
738- print (f "\n Results:" )
746+ print ("\n Results:" )
739747 print (f" Total files: { stats ['total_files' ]} " )
740748 print (f" Total executables: { stats ['total_executables' ]} " )
741- print (f" Files with multiple executables: { stats ['files_with_multiple_executables' ]} " )
749+ print (
750+ f" Files with multiple executables: { stats ['files_with_multiple_executables' ]} "
751+ )
742752
743753
744754if __name__ == "__main__" :
0 commit comments