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,15 +79,16 @@ 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
93
end = len (filename ) - 1
79
94
base = None
@@ -87,7 +102,7 @@ def _fs_match(
87
102
for i , star in enumerate (m .groups (), 1 ):
88
103
if star :
89
104
at_end = m .end (i ) == end
90
- parts = star .strip (sep ). split ( sep )
105
+ parts = split . split ( star .strip (strip ) )
91
106
if base is None :
92
107
base = os .path .join (root , filename [:m .start (i )])
93
108
last_part = len (parts )
@@ -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