Skip to content

Commit

Permalink
More optimizations. #24 cpburnz/python-pathspec#38
Browse files Browse the repository at this point in the history
  • Loading branch information
excitoon committed Aug 28, 2022
1 parent 52e3c00 commit 241a54b
Showing 1 changed file with 36 additions and 37 deletions.
73 changes: 36 additions & 37 deletions gitignorefile/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@ def parse(path, base_path=None):
if rule:
rules.append(rule)

# TODO probably combine to single regexp.

# We have negation rules. We can't use a simple "any" to evaluate them.
# Later rules override earlier rules.
return lambda file_path, is_dir=None: _match_rules(file_path, rules, base_path=base_path, is_dir=is_dir)
return _IgnoreRules(rules, base_path).match


def ignore():
Expand Down Expand Up @@ -58,8 +54,9 @@ def __call__(self, path, is_dir=None):
if parent in self.__gitignores:
break

elif os.path.isfile(os.path.join(parent, ".gitignore")):
p = parse(os.path.join(parent, ".gitignore"), base_path=parent)
parent_gitignore = os.path.join(parent, ".gitignore")
if os.path.isfile(parent_gitignore):
p = parse(parent_gitignore, base_path=parent)
add_to_children[parent] = (p, plain_paths)
plain_paths = []

Expand Down Expand Up @@ -89,36 +86,6 @@ def __call__(self, path, is_dir=None):
) # This parent comes either from first or second loop.


def _match_rules(path, rules, base_path=None, is_dir=None):
"""
Because Git allows for nested `.gitignore` files, a `base_path` value
is required for correct behavior.
"""
return_immediately = not any((r.negation for r in rules))

if is_dir is None:
is_dir = os.path.isdir(path)

if base_path is not None:
rel_path = os.path.relpath(path, base_path)
else:
rel_path = path

if rel_path.startswith(f".{os.sep}"):
rel_path = rel_path[2:]

matched = False
for rule in rules:
if rule.match(rel_path, is_dir):
if return_immediately:
return True

matched = not rule.negation

else:
return matched


def _rule_from_pattern(pattern):
"""
Take a `.gitignore` match pattern, such as "*.py[cod]" or "**/*.bak",
Expand Down Expand Up @@ -201,6 +168,38 @@ def _rule_from_pattern(pattern):
return _IgnoreRule(regexp, negation, directory_only)


class _IgnoreRules:
def __init__(self, rules, base_path):
self.__rules = rules
self.__can_return_immediately = not any((r.negation for r in rules))
self.__base_path = base_path

def match(self, path, is_dir=None):
"""
Because Git allows for nested `.gitignore` files, a `base_path` value
is required for correct behavior.
"""
if is_dir is None:
is_dir = os.path.isdir(path)

rel_path = os.path.relpath(path, self.__base_path)

if rel_path.startswith(f".{os.sep}"):
rel_path = rel_path[2:]

if self.__can_return_immediately:
return any((r.match(rel_path, is_dir) for r in self.__rules))

else:
matched = False
for rule in self.__rules:
if rule.match(rel_path, is_dir):
matched = not rule.negation

else:
return matched


class _IgnoreRule:
def __init__(self, regexp, negation, directory_only):
self.__regexp = re.compile(regexp)
Expand Down

0 comments on commit 241a54b

Please sign in to comment.