12
12
# Right half can return an empty set if not supported
13
13
SUPPORT_DIR_FD = {os .open , os .stat } <= os .supports_dir_fd and os .scandir in os .supports_fd
14
14
15
-
16
15
RE_WIN_MOUNT = (
17
- re .compile (r'\\|[a-z]:(?:\\|$)' , re .I ),
18
- re .compile (br'\\|[a-z]:(?:\\|$)' , re .I )
16
+ re .compile (r'\\|/| [a-z]:(?:\\|/ |$)' , re .I ),
17
+ re .compile (br'\\|/| [a-z]:(?:\\|/ |$)' , re .I )
19
18
)
20
19
RE_MOUNT = (
21
20
re .compile (r'/' ),
22
21
re .compile (br'/' )
23
22
)
23
+ RE_WIN_SPLIT = (
24
+ re .compile (r'\\|/' ),
25
+ re .compile (br'\\|/' )
26
+ )
27
+ RE_SPLIT = (
28
+ re .compile (r'/' ),
29
+ re .compile (br'/' )
30
+ )
31
+ RE_WIN_STRIP = (
32
+ r'\\/' ,
33
+ br'\\/'
34
+ )
35
+ RE_STRIP = (
36
+ r'/' ,
37
+ br'/'
38
+ )
24
39
25
40
26
41
class _Match (Generic [AnyStr ]):
@@ -49,8 +64,7 @@ def _fs_match(
49
64
self ,
50
65
pattern : Pattern [AnyStr ],
51
66
filename : AnyStr ,
52
- is_dir : bool ,
53
- sep : AnyStr ,
67
+ is_win : bool ,
54
68
follow : bool ,
55
69
symlinks : dict [tuple [int | None , AnyStr ], bool ],
56
70
root : AnyStr ,
@@ -65,36 +79,37 @@ def _fs_match(
65
79
We only check for the symlink if we know we are looking at a directory.
66
80
And we only call `lstat` if we can't find it in the cache.
67
81
68
- We know it's a directory if:
82
+ We know we need to check the directory if:
69
83
70
- 1. If the base is a directory, all parts are directories.
71
- 2. If we are not the last part of the `globstar`, the part is a directory.
72
- 3. If the base is a file, but the part is not at the end, it is a directory.
84
+ 1. If the match has not reached the end of the path and directory is in `globstar` match.
85
+ 2. Or the match is at the end of the path and the directory is not the last part of `globstar` match.
73
86
74
87
"""
75
88
76
89
matched = False
90
+ split = (RE_WIN_SPLIT if is_win else RE_SPLIT )[self .ptype ] # type: Any
91
+ strip = (RE_WIN_STRIP if is_win else RE_STRIP )[self .ptype ] # type: Any
77
92
78
- end = len (filename )
93
+ end = len (filename ) - 1
79
94
base = None
80
95
m = pattern .fullmatch (filename )
81
96
if m :
82
97
matched = True
83
98
# Lets look at the captured `globstar` groups and see if that part of the path
84
99
# contains symlinks.
85
100
if not follow :
86
- last = len (m .groups ())
87
101
try :
88
102
for i , star in enumerate (m .groups (), 1 ):
89
103
if star :
90
104
at_end = m .end (i ) == end
91
- parts = star .strip (sep ). split ( sep )
105
+ parts = split . split ( star .strip (strip ) )
92
106
if base is None :
93
107
base = os .path .join (root , filename [:m .start (i )])
94
- for part in parts :
108
+ last_part = len (parts )
109
+ for j , part in enumerate (parts , 1 ):
95
110
base = os .path .join (base , part )
96
111
key = (dir_fd , base )
97
- if is_dir or i != last or not at_end :
112
+ if not at_end or ( at_end and j != last_part ) :
98
113
is_link = symlinks .get (key , None )
99
114
if is_link is None :
100
115
if dir_fd is None :
@@ -125,13 +140,15 @@ def _match_real(
125
140
) -> bool :
126
141
"""Match real filename includes and excludes."""
127
142
128
- temp = '\\ ' if util .platform () == "windows" else '/'
143
+ is_win = util .platform () == "windows"
144
+
129
145
if isinstance (self .filename , bytes ):
130
- sep = os .fsencode (temp )
146
+ sep = b'/'
147
+ is_dir = (RE_WIN_SPLIT if is_win else RE_SPLIT )[1 ].match (self .filename [- 1 :]) is not None
131
148
else :
132
- sep = temp
149
+ sep = '/'
150
+ is_dir = (RE_WIN_SPLIT if is_win else RE_SPLIT )[0 ].match (self .filename [- 1 :]) is not None
133
151
134
- is_dir = self .filename .endswith (sep )
135
152
try :
136
153
if dir_fd is None :
137
154
is_file_dir = os .path .isdir (os .path .join (root , self .filename ))
@@ -153,14 +170,14 @@ def _match_real(
153
170
154
171
matched = False
155
172
for pattern in self .include :
156
- if self ._fs_match (pattern , filename , is_dir , sep , self .follow , symlinks , root , dir_fd ):
173
+ if self ._fs_match (pattern , filename , is_win , self .follow , symlinks , root , dir_fd ):
157
174
matched = True
158
175
break
159
176
160
177
if matched :
161
178
if self .exclude :
162
179
for pattern in self .exclude :
163
- if self ._fs_match (pattern , filename , is_dir , sep , True , symlinks , root , dir_fd ):
180
+ if self ._fs_match (pattern , filename , is_win , True , symlinks , root , dir_fd ):
164
181
matched = False
165
182
break
166
183
0 commit comments