13
13
#
14
14
# You should have received a copy of the GNU General Public License
15
15
# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
-
17
16
"""C/C++ dependency analyzer.
18
17
19
18
Physical dependency analyzer
36
35
37
36
from .graph import Graph
38
37
39
-
40
38
VERSION = '0.2.4' # The latest release version.
41
39
42
- _SCHEMA_FILE = os .path .join (os . path . dirname ( os . path . abspath ( __file__ )),
43
- 'config_schema.yml' )
40
+ _SCHEMA_FILE = os .path .join (
41
+ os . path . dirname ( os . path . abspath ( __file__ )), 'config_schema.yml' )
44
42
assert os .path .isfile (_SCHEMA_FILE ), 'The cppdep schema file is missing.'
45
43
assert safe_load (open (_SCHEMA_FILE )) # Will throw if invalid.
46
44
47
45
_FILE_OPEN_FLAGS = {} if sys .version [0 ] == '2' else {'errors' : 'replace' }
48
46
49
-
50
47
# Allowed common abbreviations in the code:
51
48
# ccd - Cumulative Component Dependency (CCD)
52
49
# nccd - Normalized CCD
@@ -218,8 +215,8 @@ def _find_in(include_dir):
218
215
if any (x .match (self .hfile ) for x in patterns ):
219
216
return self .hfile , package
220
217
221
- if any ( _find_in ( x ) for x in
222
- ( iter if self . with_quotes else reversed ) (include_dirs )):
218
+ direction = iter if self . with_quotes else reversed
219
+ if any ( _find_in ( x ) for x in direction (include_dirs )):
223
220
return self .hpath , None
224
221
225
222
return None , None
@@ -274,6 +271,7 @@ def dependencies(self):
274
271
275
272
def __sanitize_includes (self ):
276
273
"""Sanitizes and checks includes."""
274
+
277
275
def _check_duplicates (path , includes ):
278
276
unique_includes = set ()
279
277
for include in includes :
@@ -301,14 +299,14 @@ def _remove_redundant():
301
299
302
300
if self .hpath and self .cpath :
303
301
hfile = os .path .basename (self .hpath )
304
- if hfile not in (os . path . basename ( x . hfile )
305
- for x in self .includes_in_c ):
302
+ if hfile not in (
303
+ os . path . basename ( x . hfile ) for x in self .includes_in_c ):
306
304
warn ('include issues: missing include: '
307
305
'%s does not include %s.' % (self .cpath , hfile ))
308
306
elif hfile != os .path .basename (self .includes_in_c [0 ].hfile ):
309
307
warn ('include issues: include order: '
310
- '%s should be the first include in %s.' %
311
- ( hfile , self .cpath ))
308
+ '%s should be the first include in %s.' % ( hfile ,
309
+ self .cpath ))
312
310
_remove_duplicates ()
313
311
_remove_redundant ()
314
312
@@ -386,6 +384,7 @@ def __str__(self):
386
384
387
385
def __init_paths (self , src_paths , include_paths , alias_paths , ignore_paths ):
388
386
"""Initializes package paths."""
387
+
389
388
def _update (path_container , arg_paths , check_dir = True ):
390
389
for path in arg_paths :
391
390
path = os .path .normpath (path )
@@ -440,9 +439,9 @@ def _select_src_file(root, filename):
440
439
return
441
440
src_match = Package ._RE_SRC .match (filename )
442
441
if src_match :
443
- ( hpaths if src_match .group ('h' )
444
- else cpaths ) [strip_ext (filename )].append (
445
- file_type (_reverse (full_path ), full_path ))
442
+ src_container = hpaths if src_match .group ('h' ) else cpaths
443
+ src_container [strip_ext (filename )].append (
444
+ file_type (_reverse (full_path ), full_path ))
446
445
447
446
def _gather_files (dir_path ):
448
447
for root , _ , files in os .walk (dir_path ):
@@ -462,6 +461,7 @@ def _gather_files(dir_path):
462
461
463
462
def __pair_files (self , hpaths , cpaths ):
464
463
"""Pairs header and implementation files into components."""
464
+
465
465
# This should probably be solved with a graph algorithm.
466
466
# Find the nodes with the longest matching consecutive ancestors
467
467
# starting from the node (not the root!).
@@ -472,17 +472,21 @@ def __pair_files(self, hpaths, cpaths):
472
472
# Therefore, the algorithm to find
473
473
# the lowest common ancestor seems to lead to false answers.
474
474
def _num_consecutive_ancestors (file_one , file_two ):
475
- return sum (1 for _ in itertools .takewhile (lambda x : x [0 ] == x [1 ],
476
- zip (file_one .rev_path ,
477
- file_two .rev_path )))
475
+ return sum (1
476
+ for _ in itertools .takewhile (lambda x : x [0 ] == x [1 ],
477
+ zip (file_one .rev_path ,
478
+ file_two .rev_path )))
478
479
479
480
def _pair (hfiles , cfiles ):
480
481
assert hfiles and cfiles # Expected to have few elements.
481
- candidates = [(x , sorted (((_num_consecutive_ancestors (x , y ), y )
482
- for y in hfiles ), reverse = True ))
482
+ candidates = [(x ,
483
+ sorted (
484
+ ((_num_consecutive_ancestors (x , y ), y )
485
+ for y in hfiles ),
486
+ reverse = True ))
483
487
for x in cfiles ]
484
- candidates .sort (reverse = True ,
485
- key = lambda x : tuple (y for y , _ in x [1 ]))
488
+ candidates .sort (
489
+ reverse = True , key = lambda x : tuple (y for y , _ in x [1 ]))
486
490
for cfile , hfile_candidates in candidates :
487
491
for _ , hfile in hfile_candidates :
488
492
if hfile in hfiles :
@@ -555,8 +559,8 @@ def dependencies(self):
555
559
if self .__dep_groups is None :
556
560
self .__dep_groups = set ()
557
561
for package in self .packages .values ():
558
- self .__dep_groups .update (x . group for x in package . dependencies ()
559
- if x .group != self )
562
+ self .__dep_groups .update (
563
+ x . group for x in package . dependencies () if x .group != self )
560
564
return self .__dep_groups
561
565
562
566
def add_package (self , package ):
@@ -572,8 +576,8 @@ def add_package(self, package):
572
576
"""
573
577
if package .name in self .packages :
574
578
raise InvalidArgumentError (
575
- '%s is a duplicate package in %s group.' %
576
- ( package . name , self .name ))
579
+ '%s is a duplicate package in %s group.' % ( package . name ,
580
+ self .name ))
577
581
self .packages [package .name ] = package
578
582
579
583
@@ -658,8 +662,7 @@ def __add_package_group(pkg_group_config, pkg_groups):
658
662
package_group = PackageGroup (group_name , group_path )
659
663
660
664
for pkg_config in pkg_group_config ['packages' ]:
661
- Package (pkg_config ['name' ],
662
- package_group ,
665
+ Package (pkg_config ['name' ], package_group ,
663
666
yaml_optional_list (pkg_config , 'src' ),
664
667
yaml_optional_list (pkg_config , 'include' ),
665
668
yaml_optional_list (pkg_config , 'alias' ),
@@ -670,22 +673,24 @@ def __add_package_group(pkg_group_config, pkg_groups):
670
673
671
674
def __gather_include_dirs (self ):
672
675
"""Gathers include directories from packages."""
676
+
673
677
def _add_from (groups ):
674
678
for group in groups .values ():
675
679
for package in group .packages .values ():
676
680
self .include_dirs .extend (package .include_paths )
681
+
677
682
_add_from (self .internal_groups )
678
683
_add_from (self .external_groups )
679
684
680
685
def __gather_aliases (self ):
681
686
"""Gathers aliases for *external* packages lazy include search."""
682
687
for group in self .external_groups .values ():
683
688
for package in group .packages .values ():
684
- self .__package_aliases .extend (( x , package )
685
- for x in package .alias_paths )
689
+ self .__package_aliases .extend (
690
+ ( x , package ) for x in package .alias_paths )
686
691
self .__package_aliases .sort ()
687
- assert (len (set (x for x , _ in self .__package_aliases )) ==
688
- len ( self .__package_aliases )), "Ambiguous aliases to packages"
692
+ assert (len (set (x for x , _ in self .__package_aliases )) == len (
693
+ self .__package_aliases )), "Ambiguous aliases to packages"
689
694
690
695
def __gather_include_patterns (self ):
691
696
"""Gathers and compiles include patterns into regex objects."""
@@ -708,16 +713,16 @@ def locate(self, include, component):
708
713
Raises:
709
714
AnalysisError: Failure to associate a header to a component.
710
715
"""
716
+
711
717
def _find_external_package (hpath ):
712
718
for path , package in reversed (self .__package_aliases ):
713
719
if path_isancestor (path , hpath ):
714
720
return package
715
721
raise AnalysisError ('include error: Cannot associate '
716
722
'%s file with any component.' % hpath )
717
723
718
- hpath , package = include .locate (component .working_dir ,
719
- self .include_dirs ,
720
- self .__include_patterns )
724
+ hpath , package = include .locate (
725
+ component .working_dir , self .include_dirs , self .__include_patterns )
721
726
722
727
if hpath is None :
723
728
return False
@@ -727,11 +732,10 @@ def _find_external_package(hpath):
727
732
component .dep_components .add (dep_component )
728
733
else :
729
734
if hpath in self ._external_components :
730
- component .dep_components .add (
731
- self ._external_components [hpath ])
735
+ component .dep_components .add (self ._external_components [hpath ])
732
736
else :
733
- dep_component = ExternalComponent (
734
- hpath , package or _find_external_package (hpath ))
737
+ dep_component = ExternalComponent (hpath , package or
738
+ _find_external_package (hpath ))
735
739
component .dep_components .add (dep_component )
736
740
self ._external_components [hpath ] = dep_component
737
741
return True
@@ -768,6 +772,7 @@ def make_components(self):
768
772
769
773
def analyze (self , printer , args ):
770
774
"""Runs the analysis."""
775
+
771
776
def _analyze (graph_name , digraph ):
772
777
digraph .analyze ()
773
778
digraph .print_cycles (printer )
@@ -803,8 +808,8 @@ def _analyze(graph_name, digraph):
803
808
continue
804
809
printer ('\n ' + '#' * 80 )
805
810
printer ('analyzing dependencies among components in '
806
- 'the specified package %s.%s ...' %
807
- ( group_name , pkg_name ))
811
+ 'the specified package %s.%s ...' % ( group_name ,
812
+ pkg_name ))
808
813
_analyze ('_' .join ((group_name , pkg_name )),
809
814
Graph (package .components ,
810
815
lambda x : (i if i .package == package
0 commit comments