From 7b9266afea5ba72f63d7459e9cb8040d89bd1dc2 Mon Sep 17 00:00:00 2001 From: Vladimir Chebotarev Date: Sun, 28 Aug 2022 14:31:45 +0300 Subject: [PATCH] Perfect processing, 35% faster than `pathspec`. #24 cpburnz/python-path-specification#38 --- gitignorefile/__init__.py | 19 ++++++++++++++----- tests/test_cache.py | 7 ++++++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/gitignorefile/__init__.py b/gitignorefile/__init__.py index e7db8e3..17dde9f 100644 --- a/gitignorefile/__init__.py +++ b/gitignorefile/__init__.py @@ -41,8 +41,8 @@ def __call__(self, path, is_dir=None): parent_gitignore = parent.join(".gitignore") if parent_gitignore.isfile(): - p = parse(str(parent_gitignore), base_path=parent) - add_to_children[parent] = (p, plain_paths) + matches = parse(str(parent_gitignore), base_path=parent) + add_to_children[parent] = (matches, plain_paths) plain_paths = [] else: @@ -50,9 +50,13 @@ def __call__(self, path, is_dir=None): else: for plain_path in plain_paths: - self.__gitignores[plain_path] = [] + assert plain_path.parts not in self.__gitignores + self.__gitignores[plain_path.parts] = [] - if not add_to_children: + if add_to_children: + plain_paths.clear() + + else: return False for parent, (_, parent_plain_paths) in reversed(list(add_to_children.items())): @@ -64,8 +68,13 @@ def __call__(self, path, is_dir=None): self.__gitignores[parent.parts].reverse() for plain_path in parent_plain_paths: + assert plain_path.parts not in self.__gitignores self.__gitignores[plain_path.parts] = self.__gitignores[parent.parts] + for plain_path in plain_paths: + assert plain_path.parts not in self.__gitignores + self.__gitignores[plain_path.parts] = self.__gitignores[parent.parts] + return any( (m(path, is_dir=is_dir) for m in self.__gitignores[parent.parts]) ) # This parent comes either from first or second loop. @@ -114,7 +123,7 @@ def isdir(self): def __str__(self): if self.__joined is None: - self.__joined = "/".join(self.__parts) + self.__joined = "/".join(self.__parts) if self.__parts != ("",) else "/" return self.__joined diff --git a/tests/test_cache.py b/tests/test_cache.py index 1f7a209..bfe8e5b 100644 --- a/tests/test_cache.py +++ b/tests/test_cache.py @@ -43,6 +43,8 @@ def __call__(self, path): "/", ], [ + "/home/vladimir/project/directory/subdirectory/subdirectory/file.txt", + "/home/vladimir/project/directory/subdirectory/subdirectory/file2.txt", "/home/vladimir/project/directory/subdirectory/file.txt", "/home/vladimir/project/directory/subdirectory/file2.txt", "/home/vladimir/project/directory/.gitignore", @@ -75,12 +77,15 @@ def mock_stat(path): matches = gitignorefile.Cache() self.assertTrue(matches("/home/vladimir/project/directory/subdirectory/file.txt")) self.assertTrue(matches("/home/vladimir/project/directory/subdirectory/file2.txt")) + self.assertTrue(matches("/home/vladimir/project/directory/subdirectory/subdirectory/file.txt")) + self.assertTrue(matches("/home/vladimir/project/directory/subdirectory/subdirectory/file2.txt")) + self.assertFalse(matches("/home/vladimir/project/directory/subdirectory/subdirectory/file3.txt")) self.assertTrue(matches("/home/vladimir/project/directory/file.txt")) self.assertTrue(matches("/home/vladimir/project/directory/file2.txt")) self.assertFalse(matches("/home/vladimir/project/file.txt")) self.assertEqual(statistics["open"], 2) - self.assertEqual(statistics["stat"], 6 + 5) + self.assertEqual(statistics["stat"], 7 + 8) def test_wrong_symlink(self): with tempfile.TemporaryDirectory() as d: