Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor path handling for platform independence #67

Closed
wants to merge 1 commit into from

Conversation

vrocky
Copy link

@vrocky vrocky commented May 27, 2024

This commit addresses issues with path handling in the Gitignore parsing library, ensuring compatibility across different platforms such as Unix and Windows. Key changes include:

  • Updated the regular expression handling in the fnmatch_pathname_to_regex function to accommodate both Unix and Windows path separators.
  • Added path normalization before processing to ensure consistency in path representation, replacing backslashes with forward slashes.
  • Modified the construction of regular expressions to handle both types of path separators, making the matching process platform-independent.

These adjustments enable the library to correctly parse Gitignore files on Windows systems, resolving issues with path matching and improving overall compatibility.

This commit addresses issues with path handling in the Gitignore parsing library, ensuring compatibility across different platforms such as Unix and Windows. Key changes include:

- Updated the regular expression handling in the fnmatch_pathname_to_regex function to accommodate both Unix and Windows path separators.
- Added path normalization before processing to ensure consistency in path representation, replacing backslashes with forward slashes.
- Modified the construction of regular expressions to handle both types of path separators, making the matching process platform-independent.

These adjustments enable the library to correctly parse Gitignore files on Windows systems, resolving issues with path matching and improving overall compatibility.
@vrocky vrocky closed this May 28, 2024
@vrocky
Copy link
Author

vrocky commented May 28, 2024

There is slight error with windows but this is not the solution to it

Here are my tests for windows where test_wildcard and test_trailingspaces is failing

from unittest.mock import patch, mock_open
from pathlib import Path, WindowsPath
from tempfile import TemporaryDirectory

from gitignore_parser import parse_gitignore

from unittest import TestCase, main


class Test(TestCase):
    def test_simple(self):
        matches = _parse_gitignore_string(
            '__pycache__/\n'
            '*.py[cod]',
            fake_base_dir='C:\\Users\\michael'
        )
        self.assertFalse(matches('C:\\Users\\michael\\main.py'))
        self.assertTrue(matches('C:\\Users\\michael\\main.pyc'))
        self.assertTrue(matches('C:\\Users\\michael\\dir\\main.pyc'))
        self.assertTrue(matches('C:\\Users\\michael\\__pycache__'))

    def test_incomplete_filename(self):
        matches = _parse_gitignore_string('o.py', fake_base_dir='C:\\Users\\michael')
        self.assertTrue(matches('C:\\Users\\michael\\o.py'))
        self.assertFalse(matches('C:\\Users\\michael\\foo.py'))
        self.assertFalse(matches('C:\\Users\\michael\\o.pyc'))
        self.assertTrue(matches('C:\\Users\\michael\\dir\\o.py'))
        self.assertFalse(matches('C:\\Users\\michael\\dir\\foo.py'))
        self.assertFalse(matches('C:\\Users\\michael\\dir\\o.pyc'))

    def test_wildcard(self):
        matches = _parse_gitignore_string(
            'hello.*',
            fake_base_dir='C:\\Users\\michael'
        )
        self.assertTrue(matches('C:\\Users\\michael\\hello.txt'))
        self.assertTrue(matches('C:\\Users\\michael\\hello.foobar\\'))
        self.assertTrue(matches('C:\\Users\\michael\\dir\\hello.txt'))
        self.assertTrue(matches('C:\\Users\\michael\\hello.'))
        self.assertFalse(matches('C:\\Users\\michael\\hello'))
        self.assertFalse(matches('C:\\Users\\michael\\helloX'))

    def test_anchored_wildcard(self):
        matches = _parse_gitignore_string(
            '/hello.*',
            fake_base_dir='C:\\Users\\michael'
        )
        self.assertTrue(matches('C:\\Users\\michael\\hello.txt'))
        self.assertTrue(matches('C:\\Users\\michael\\hello.c'))
        self.assertFalse(matches('C:\\Users\\michael\\a\\hello.java'))

    def test_trailingspaces(self):
        matches = _parse_gitignore_string(
            'ignoretrailingspace \n'
            'notignoredspace\\ \n'
            'partiallyignoredspace\\  \n'
            'partiallyignoredspace2 \\  \n'
            'notignoredmultiplespace\\ \\ \\ ',
            fake_base_dir='C:\\Users\\michael'
        )
        self.assertTrue(matches('C:\\Users\\michael\\ignoretrailingspace'))
        self.assertFalse(matches('C:\\Users\\michael\\ignoretrailingspace '))
        self.assertTrue(matches('C:\\Users\\michael\\partiallyignoredspace '))
        self.assertFalse(matches('C:\\Users\\michael\\partiallyignoredspace  '))
        self.assertFalse(matches('C:\\Users\\michael\\partiallyignoredspace'))
        self.assertTrue(matches('C:\\Users\\michael\\partiallyignoredspace2  '))
        self.assertFalse(matches('C:\\Users\\michael\\partiallyignoredspace2   '))
        self.assertFalse(matches('C:\\Users\\michael\\partiallyignoredspace2 '))
        self.assertFalse(matches('C:\\Users\\michael\\partiallyignoredspace2'))
        self.assertTrue(matches('C:\\Users\\michael\\notignoredspace '))
        self.assertFalse(matches('C:\\Users\\michael\\notignoredspace'))
        self.assertTrue(matches('C:\\Users\\michael\\notignoredmultiplespace   '))
        self.assertFalse(matches('C:\\Users\\michael\\notignoredmultiplespace'))

    def test_supports_path_type_argument(self):
        matches = _parse_gitignore_string(
            'file1\n!file2', fake_base_dir='C:\\Users\\michael'
        )
        self.assertTrue(matches(WindowsPath('C:\\Users\\michael\\file1')))
        self.assertFalse(matches(WindowsPath('C:\\Users\\michael\\file2')))

"""
    def test_symlink_to_another_directory(self):
        with TemporaryDirectory() as project_dir:
            with TemporaryDirectory() as another_dir:
                matches = \
                    _parse_gitignore_string('link', fake_base_dir=project_dir)

                # Create a symlink to another directory.
                link = Path(project_dir, 'link')
                target = Path(another_dir, 'target')
                link.symlink_to(target)

                # Check the intended behavior according to
                # https://git-scm.com/docs/gitignore#_notes:
                # Symbolic links are not followed and are matched as if they
                # were regular files.
                self.assertTrue(matches(link))
"""


def _parse_gitignore_string(data: str, fake_base_dir: str = None):
    with patch('builtins.open', mock_open(read_data=data)):
        success = parse_gitignore(f'{fake_base_dir}\\.gitignore', fake_base_dir)
        return success

if __name__ == '__main__':
    main()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants