3939from commoncode .datautils import List
4040from commoncode .datautils import Mapping
4141from commoncode .datautils import String
42+ from commoncode .fileset import is_included
4243from commoncode .filetype import is_file as filetype_is_file
4344from commoncode .filetype import is_special
4445from commoncode .fileutils import as_posixpath
6263
6364# Tracing flags
6465TRACE = False
65- TRACE_DEEP = False
66+ TRACE_DEEP = True
6667
6768
6869def logger_debug (* args ):
@@ -98,7 +99,7 @@ def skip_ignored(location):
9899 if TRACE_DEEP :
99100 logger_debug ()
100101 logger_debug (
101- "Codebase.populate: walk: ignored loc :" ,
102+ "Codebase.populate: walk: skip_ignored :" ,
102103 location ,
103104 "ignored:" ,
104105 ignored (location ),
@@ -109,6 +110,42 @@ def skip_ignored(location):
109110 return is_special (location ) or ignored (location )
110111
111112
113+ def is_ignored (location , includes = None , excludes = None ):
114+
115+ excludes = {
116+ pattern : 'User ignore: Supplied by --ignore' for pattern in excludes
117+ }
118+
119+ includes = {
120+ pattern : 'User include: Supplied by --include' for pattern in includes
121+ }
122+
123+ included_from_options = is_included (
124+ path = location ,
125+ includes = includes ,
126+ excludes = excludes ,
127+ )
128+
129+ if TRACE_DEEP :
130+ logger_debug (
131+ "Codebase.populate: walk: is_ignored:" ,
132+ "is_ignored: location:" ,
133+ location ,
134+ "included_from_options:" ,
135+ included_from_options ,
136+ "skip_ignored" ,
137+ skip_ignored (location )
138+ )
139+
140+ if skip_ignored (location ) or not included_from_options :
141+ if TRACE_DEEP :
142+ logger_debug ("is_ignored: location:" , location , "is_skipped" ,)
143+
144+ return True
145+
146+ return False
147+
148+
112149def depth_walk (
113150 root_location ,
114151 max_depth ,
@@ -202,6 +239,8 @@ class Codebase:
202239 __slots__ = (
203240 "max_depth" ,
204241 "location" ,
242+ "includes" ,
243+ "ignores" ,
205244 "has_single_resource" ,
206245 "resource_attributes" ,
207246 "resource_class" ,
@@ -236,6 +275,8 @@ def __init__(
236275 max_in_memory = 10000 ,
237276 max_depth = 0 ,
238277 paths = tuple (),
278+ ignores = tuple (),
279+ includes = tuple (),
239280 * args ,
240281 ** kwargs ,
241282 ):
@@ -298,6 +339,8 @@ def __init__(
298339
299340 # finally populate
300341 self .paths = self ._prepare_clean_paths (paths )
342+ self .ignores = ignores
343+ self .includes = includes
301344 self ._populate ()
302345
303346 def _prepare_clean_paths (self , paths = tuple ()):
@@ -461,11 +504,17 @@ def _populate(self):
461504 return
462505
463506 if self .paths :
464- return self ._create_resources_from_paths (root = root , paths = self .paths )
507+ # In case of a list of full paths, we create resources without walking
508+ return self ._create_resources_from_full_paths (root = root , paths = self .paths )
509+ # In case we have multiple
465510 else :
466- return self ._create_resources_from_root (root = root )
511+ return self ._create_resources_from_root (
512+ root = root ,
513+ includes = self .includes ,
514+ ignores = self .ignores ,
515+ )
467516
468- def _create_resources_from_paths (self , root , paths ):
517+ def _create_resources_from_full_paths (self , root , paths ):
469518 # without paths we iterate the provided paths. We report an error
470519 # if a path is missing on disk.
471520
@@ -483,22 +532,21 @@ def _create_resources_from_paths(self, root, paths):
483532 msg = f"ERROR: cannot populate codebase: path: { path !r} not found in { res_loc !r} "
484533 self .errors .append (msg )
485534 raise Exception (path , join (base_location , path ))
486- continue
487535
488536 # create all parents. The last parent is the one we want to use
489537 parent = root
490538 if TRACE :
491- logger_debug ("Codebase._create_resources_from_paths : parent" , parent )
539+ logger_debug ("Codebase._create_resources_from_full_paths : parent" , parent )
492540 for parent_path in get_ancestor_paths (path , include_self = False ):
493541 if TRACE :
494542 logger_debug (
495- f" Codebase._create_resources_from_paths : parent_path: { parent_path !r} "
543+ f" Codebase._create_resources_from_full_paths : parent_path: { parent_path !r} "
496544 )
497545 if not parent_path :
498546 continue
499547 newpar = parents_by_path .get (parent_path )
500548 if TRACE :
501- logger_debug (" Codebase._create_resources_from_paths : newpar" , repr (newpar ))
549+ logger_debug (" Codebase._create_resources_from_full_paths : newpar" , repr (newpar ))
502550
503551 if not newpar :
504552 newpar = self ._get_or_create_resource (
@@ -509,7 +557,7 @@ def _create_resources_from_paths(self, root, paths):
509557 )
510558 if not newpar :
511559 raise Exception (
512- "ERROR: Codebase._create_resources_from_paths :"
560+ "ERROR: Codebase._create_resources_from_full_paths :"
513561 f" cannot create parent for: { parent_path !r} "
514562 )
515563 parent = newpar
@@ -518,7 +566,7 @@ def _create_resources_from_paths(self, root, paths):
518566
519567 if TRACE :
520568 logger_debug (
521- f" Codebase._create_resources_from_paths :" ,
569+ f" Codebase._create_resources_from_full_paths :" ,
522570 f"created newpar: { newpar !r} " ,
523571 )
524572
@@ -529,10 +577,10 @@ def _create_resources_from_paths(self, root, paths):
529577 is_file = isfile (res_loc ),
530578 )
531579 if TRACE :
532- logger_debug ("Codebase._create_resources_from_paths : resource" , res )
580+ logger_debug ("Codebase._create_resources_from_full_paths : resource" , res )
533581
534- def _create_resources_from_root (self , root ):
535- # without paths we walks the root location top-down
582+ def _create_resources_from_root (self , root , includes , ignores ):
583+ # without paths we walk the root location top-down
536584
537585 # track resources parents by location during construction.
538586 # NOTE: this cannot exhaust memory on a large codebase, because we do
@@ -545,9 +593,15 @@ def err(_error):
545593 f"ERROR: cannot populate codebase: { _error } \n { traceback .format_exc ()} "
546594 )
547595
596+ skip_ignored = partial (is_ignored , includes = includes , excludes = ignores )
597+
598+ if TRACE_DEEP :
599+ logger_debug (f"parents_by_loc: { parents_by_loc } , ignores: { ignores } , includes: { includes } " )
600+
548601 # Walk over the directory and build the resource tree
549602 for top , dirs , files in depth_walk (
550603 root_location = root .location ,
604+ skip_ignored = skip_ignored ,
551605 max_depth = self .max_depth ,
552606 error_handler = err ,
553607 ):
@@ -557,6 +611,7 @@ def err(_error):
557611 top = top ,
558612 dirs = dirs ,
559613 files = files ,
614+ skip_ignored = skip_ignored ,
560615 ):
561616 # on the plain, bare FS, files cannot be parents
562617 if not created .is_file :
@@ -574,6 +629,8 @@ def _create_resources(self, parent, top, dirs, files, skip_ignored=skip_ignored)
574629 for name in names :
575630 location = join (top , name )
576631 if skip_ignored (location ):
632+ if TRACE_DEEP :
633+ logger_debug (f"_create_resources, depth_walk loop: ignored location: { location } " )
577634 continue
578635 res = self ._get_or_create_resource (
579636 name = name ,
0 commit comments