fix(util): ensure bare * and ? in non-** glob patterns do not match / (#1732)

This commit is contained in:
arimu1 committed 2026-07-23 12:22:05 +07:00
1 parent ac256f3630
commit 70d32f2453
3 files changed
+47 -2

No files matched your search

+1
View File
@@ -6,6 +6,7 @@ Status of the `main` branch. Changes prior to the next official version change w
- Add Grok Build support (context `grok`, setup CLI, hooks)
- The `languages` key in project configurations was changed to `language_servers` to better reflect
the actual semantics (configurations are automatically migrated)
- Fix: `glob_match` bare `*` and `?` in non-`**` patterns matched across `/`, contradicting its documented behavior #1732
* Language Servers:
- Allow language server priorities to be configured in `serena_config.yml` (for auto-detection during
+40 -2
View File
@@ -5,6 +5,7 @@ import re
from collections.abc import Callable
from dataclasses import dataclass, field
from enum import StrEnum
from functools import lru_cache
from typing import Any, Literal, Self
from bs4 import BeautifulSoup
@@ -240,6 +241,43 @@ def expand_braces(pattern: str) -> list[str]:
return patterns
@lru_cache(maxsize=256)
def _translate_glob_no_double_star(pattern: str) -> str:
res = []
i = 0
n = len(pattern)
while i < n:
c = pattern[i]
i += 1
if c == "*":
if not res or res[-1] != "[^/]*":
res.append("[^/]*")
elif c == "?":
res.append("[^/]")
elif c == "[":
j = i
if j < n and pattern[j] == "!":
j += 1
if j < n and pattern[j] == "]":
j += 1
while j < n and pattern[j] != "]":
j += 1
if j >= n:
res.append(r"\[")
else:
stuff = pattern[i:j]
if stuff.startswith("!"):
stuff = "^" + stuff[1:]
elif stuff.startswith("^"):
stuff = r"\^" + stuff
res.append(f"[{stuff}]")
i = j + 1
else:
res.append(re.escape(c))
inner = "".join(res)
return f"(?s:{inner})\\Z"
def glob_match(pattern: str, path: str) -> bool:
"""
Match a file path against a glob pattern.
@@ -289,8 +327,8 @@ def glob_match(pattern: str, path: str) -> bool:
return False
else:
# Simple pattern without **, use fnmatch directly
return fnmatch.fnmatch(path, pattern)
# Simple pattern without **, translate bare * and ? to not match /
return bool(re.match(_translate_glob_no_double_star(pattern), path))
class GlobMatcher:
+6
View File
@@ -593,10 +593,16 @@ class TestGlobMatch:
[
# Basic wildcard patterns
("*.py", "file.py", True),
("*.py", "src/file.py", False),
("*.py", "file.txt", False),
("*agent.py", "agent.py", True),
("*agent.py", "process_isolated_agent.py", True),
("*agent.py", "src/agent.py", False),
("*agent.py", "agent_test.py", False),
("a?b.py", "acb.py", True),
("a?b.py", "a/b.py", False),
("src/*.py", "src/file.py", True),
("src/*.py", "src/sub/file.py", False),
# Double asterisk patterns
("**agent.py", "agent.py", True),
("**agent.py", "src/agent.py", True),