from __future__ import annotations from fnmatch import fnmatch from pathlib import Path IGNORE_FILE_NAME = '.nanoshareignore' DEFAULT_IGNORE_PATTERNS = [ IGNORE_FILE_NAME, '.comments/', '.env', '.env.*', '.venv/', 'venv/', '__pycache__/', '.pytest_cache/', '.mypy_cache/', '.ruff_cache/', '.git/', '.hg/', '.svn/', '.DS_Store', 'Thumbs.db', 'desktop.ini', '$RECYCLE.BIN/', 'System Volume Information/', ] def load_ignore_patterns(root: Path, extra_patterns: list[str] | None = None) -> list[str]: patterns = list(DEFAULT_IGNORE_PATTERNS) ignore_file = root / IGNORE_FILE_NAME if ignore_file.is_file(): for line in ignore_file.read_text().splitlines(): pattern = line.strip() if pattern and not pattern.startswith('#'): patterns.append(pattern) patterns.extend(pattern for pattern in extra_patterns or [] if pattern) return patterns def is_ignored(rel_path: str, patterns: list[str]) -> bool: path = rel_path.strip('/') parts = path.split('/') for pattern in patterns: normalized = pattern.strip().replace('\\', '/').strip('/') if not normalized: continue if pattern.endswith('/'): if path == normalized or path.startswith(f'{normalized}/'): return True continue if '/' in normalized: if fnmatch(path, normalized): return True elif any(fnmatch(part, normalized) for part in parts): return True return False