Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions cycode/cli/files_collector/walk_ignore.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import os
from collections.abc import Generator, Iterable

from cycode.cli.logger import logger
from cycode.cli.logger import get_logger
from cycode.cli.utils.ignore_utils import IgnoreFilterManager

logger = get_logger('Ignores')

_SUPPORTED_IGNORE_PATTERN_FILES = {
'.gitignore',
'.cycodeignore',
Expand All @@ -30,7 +32,7 @@ def _collect_top_level_ignore_files(path: str) -> list[str]:
for ignore_file in _SUPPORTED_IGNORE_PATTERN_FILES:
ignore_file_path = os.path.join(dir_path, ignore_file)
if os.path.exists(ignore_file_path):
logger.debug('Apply top level ignore file: %s', ignore_file_path)
logger.debug('Reading top level ignore file: %s', ignore_file_path)
ignore_files.append(ignore_file_path)
return ignore_files

Expand All @@ -41,4 +43,17 @@ def walk_ignore(path: str) -> Generator[tuple[str, list[str], list[str]], None,
global_ignore_file_paths=_collect_top_level_ignore_files(path),
global_patterns=_DEFAULT_GLOBAL_IGNORE_PATTERNS,
)
yield from ignore_filter_manager.walk()
for dirpath, dirnames, filenames, ignored_dirnames, ignored_filenames in ignore_filter_manager.walk_with_ignored():
rel_dirpath = '' if dirpath == path else os.path.relpath(dirpath, path)
display_dir = rel_dirpath or '.'
for is_dir, names in (
(True, ignored_dirnames),
(False, ignored_filenames),
):
for name in names:
full_path = os.path.join(path, display_dir, name)
if is_dir:
full_path = os.path.join(full_path, '*')
logger.debug('Ignoring match %s', full_path)

yield dirpath, dirnames, filenames
31 changes: 25 additions & 6 deletions cycode/cli/utils/ignore_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,19 +388,38 @@ def is_ignored(self, path: str) -> Optional[bool]:
return matches[-1].is_exclude
return None

def walk(self, **kwargs) -> Generator[tuple[str, list[str], list[str]], None, None]:
"""Wrap os.walk() without ignored files and subdirectories and kwargs are passed to walk."""
def walk_with_ignored(
self, **kwargs
) -> Generator[tuple[str, list[str], list[str], list[str], list[str]], None, None]:
"""Wrap os.walk() and also return lists of ignored directories and files.

Yields tuples: (dirpath, included_dirnames, included_filenames, ignored_dirnames, ignored_filenames)
"""
for dirpath, dirnames, filenames in os.walk(self.path, topdown=True, **kwargs):
rel_dirpath = '' if dirpath == self.path else os.path.relpath(dirpath, self.path)

original_dirnames = list(dirnames)
included_dirnames = []
ignored_dirnames = []
for d in original_dirnames:
if self.is_ignored(os.path.join(rel_dirpath, d)):
ignored_dirnames.append(d)
else:
included_dirnames.append(d)

# decrease recursion depth of os.walk() by ignoring subdirectories because of topdown=True
# slicing ([:]) is mandatory to change dict in-place!
dirnames[:] = [d for d in dirnames if not self.is_ignored(os.path.join(rel_dirpath, d))]
dirnames[:] = included_dirnames

# remove ignored files
filenames = [f for f in filenames if not self.is_ignored(os.path.join(rel_dirpath, f))]
included_filenames = []
ignored_filenames = []
for f in filenames:
if self.is_ignored(os.path.join(rel_dirpath, f)):
ignored_filenames.append(f)
else:
included_filenames.append(f)

yield dirpath, dirnames, filenames
yield dirpath, dirnames, included_filenames, ignored_dirnames, ignored_filenames

@classmethod
def build(
Expand Down