Coverage for src\llm_code_lens\utils\gitignore.py: 25%

36 statements  

« prev     ^ index     » next       coverage.py v7.7.0, created at 2025-05-25 12:07 +0300

1""" 

2Gitignore Parser Utility Module 

3Handles parsing and applying .gitignore patterns. 

4""" 

5 

6from pathlib import Path 

7import re 

8from typing import List, Optional 

9 

10class GitignoreParser: 

11 """ 

12 Parses .gitignore files and provides methods to check if a file should be ignored. 

13 

14 Attributes: 

15 root_path (Path): The root directory where the .gitignore file is located. 

16 patterns (List[str]): List of ignore patterns parsed from .gitignore. 

17 """ 

18 

19 def __init__(self, root_path: Path): 

20 """Initialize with the root path containing .gitignore.""" 

21 self.root_path = root_path 

22 self.patterns = [] 

23 

24 def load_gitignore(self) -> None: 

25 """ 

26 Load and parse the .gitignore file from the root directory. 

27 This method populates the patterns list. 

28 """ 

29 gitignore_path = self.root_path / '.gitignore' 

30 

31 if not gitignore_path.exists(): 

32 return 

33 

34 try: 

35 with open(gitignore_path, 'r') as f: 

36 for line in f: 

37 # Skip empty lines and comments 

38 line = line.strip() 

39 if line and not line.startswith('#'): 

40 self.patterns.append(line) 

41 except Exception as e: 

42 print(f"Warning: Error reading {gitignore_path}: {e}") 

43 

44 def get_ignore_patterns(self) -> List[str]: 

45 """ 

46 Get the list of ignore patterns. 

47 

48 Returns: 

49 List[str]: List of ignore patterns. 

50 """ 

51 return self.patterns 

52 

53 def should_ignore(self, path: Path) -> bool: 

54 """ 

55 Check if a file or directory matches any of the .gitignore patterns. 

56 

57 Args: 

58 path (Path): The file or directory to check. 

59 

60 Returns: 

61 bool: True if the path should be ignored, False otherwise. 

62 """ 

63 path_str = str(path.relative_to(self.root_path)) 

64 

65 for pattern in self.patterns: 

66 # Convert gitignore pattern to regex 

67 regex_pattern = self._convert_to_regex(pattern) 

68 

69 # Check if the path matches the pattern 

70 if re.search(regex_pattern, path_str): 

71 return True 

72 

73 return False 

74 

75 def _convert_to_regex(self, pattern: str) -> str: 

76 """ 

77 Convert a gitignore pattern to a regular expression. 

78 

79 Args: 

80 pattern (str): The gitignore pattern. 

81 

82 Returns: 

83 str: The equivalent regular expression. 

84 """ 

85 # Escape special regex characters in the pattern 

86 escaped_pattern = re.escape(pattern) 

87 

88 # Handle wildcards and special patterns 

89 escaped_pattern = ( 

90 escaped_pattern.replace(r'\*', '.*') # * -> .* 

91 .replace(r'\?', '.') # ? -> . 

92 .replace(r'\[', '[') # [ -> [ 

93 .replace(r'\]', ']') # ] -> ] 

94 ) 

95 

96 # Handle directory-specific patterns 

97 if pattern.endswith('/'): 

98 escaped_pattern += '/' 

99 elif not pattern.startswith('/'): 

100 # If the pattern doesn't start with a slash, it's relative to the current directory 

101 escaped_pattern = f'.*{escaped_pattern}' 

102 

103 return escaped_pattern