diff --git a/src/codeguard/utils/ignore.py b/src/codeguard/utils/ignore.py new file mode 100644 index 0000000..d0c981f --- /dev/null +++ b/src/codeguard/utils/ignore.py @@ -0,0 +1,89 @@ +"""Ignore file parser for CodeGuard.""" + +from pathlib import Path + + +class IgnoreParser: + def __init__(self): + self.patterns: list[dict] = [] + + def load_from_file(self, file_path: Path) -> None: + if not file_path.exists(): + return + + with open(file_path, "r") as f: + for line in f: + line = line.strip() + if line and not line.startswith("#"): + self.add_pattern(line) + + def add_pattern(self, pattern: str) -> None: + negate = pattern.startswith("!") + if negate: + pattern = pattern[1:] + + if pattern.startswith("/"): + pattern = pattern[1:] + is_absolute = True + else: + is_absolute = False + + self.patterns.append({ + "pattern": pattern, + "negate": negate, + "is_absolute": is_absolute, + }) + + def should_ignore(self, path: str) -> bool: + path_parts = path.split("/") + + for p in self.patterns: + if p["is_absolute"]: + if self._match_absolute(p["pattern"], path): + return not p["negate"] + else: + if self._match_relative(p["pattern"], path_parts): + return not p["negate"] + + return False + + def _match_absolute(self, pattern: str, path: str) -> bool: + if pattern.endswith("/"): + pattern = pattern.rstrip("/") + return path.startswith(pattern + "/") or path == pattern + + return pattern in path or self._glob_match(pattern, path) + + def _match_relative(self, pattern: str, path_parts: list[str]) -> bool: + pattern_parts = pattern.split("/") + + if pattern.startswith("**"): + return True + + if len(pattern_parts) > len(path_parts): + return False + + for i, pp in enumerate(pattern_parts): + if pp == "**": + return True + if pp == "*": + continue + if i >= len(path_parts) or not self._glob_match(pp, path_parts[i]): + return False + + return True + + def _glob_match(self, pattern: str, string: str) -> bool: + if pattern == "*": + return True + + if pattern.startswith("*") and pattern.endswith("*"): + return pattern[1:-1] in string + + if pattern.startswith("*"): + return string.endswith(pattern[1:]) + + if pattern.endswith("*"): + return string.startswith(pattern[:-1]) + + return pattern == string