8000 [Finder] Fix gitignore regex build with "**" · symfony/symfony@ce22d5d · GitHub
[go: up one dir, main page]

Skip to content

Commit ce22d5d

Browse files
mvorisekfabpot
authored andcommitted
[Finder] Fix gitignore regex build with "**"
1 parent dffdc71 commit ce22d5d

File tree

2 files changed

+139
-37
lines changed

2 files changed

+139
-37
lines changed

src/Symfony/Component/Finder/Gitignore.php

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,20 +68,16 @@ private static function lineToRegex(string $gitignoreLine): string
6868
$isAbsolute = false;
6969
}
7070

71-
$parts = array_map(function (string $v): string {
72-
$v = preg_quote(str_replace('\\', '', $v), '~');
73-
$v = preg_replace_callback('~\\\\\[([^\[\]]*)\\\\\]~', function (array $matches): string {
74-
return '['.str_replace('\\-', '-', $matches[1]).']';
75-
}, $v);
76-
$v = preg_replace('~\\\\\*\\\\\*~', '[^/]+(?:/[^/]+)*', $v);
77-
$v = preg_replace('~\\\\\*~', '[^/]*', $v);
78-
$v = preg_replace('~\\\\\?~', '[^/]', $v);
79-
80-
return $v;
81-
}, explode('/', $gitignoreLine));
71+
$regex = preg_quote(str_replace('\\', '', $gitignoreLine), '~');
72+
$regex = preg_replace_callback('~\\\\\[((?:\\\\!)?)([^\[\]]*)\\\\\]~', function (array $matches): string {
73+
return '['.('' !== $matches[1] ? '^' : '').str_replace('\\-', '-', $matches[2]).']';
74+
}, $regex);
75+
$regex = preg_replace('~(?:(?:\\\\\*){2,}(/?))+~', '(?:(?:(?!//).(?<!//))+$1)?', $regex);
76+
$regex = preg_replace('~\\\\\*~', '[^/]*', $regex);
77+
$regex = preg_replace('~\\\\\?~', '[^/]', $regex);
8278

8379
return ($isAbsolute ? '' : '(?:[^/]+/)*')
84-
.implode('/', $parts)
85-
.('' !== end($parts) ? '(?:$|/)' : '');
80+
.$regex
81+
.('/' !== substr($gitignoreLine, -1) ? '(?:$|/)' : '');
8682
}
8783
}

src/Symfony/Component/Finder/Tests/GitignoreTest.php

Lines changed: 130 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,9 @@ public function provider(): array
8888
[],
8989
],
9090
[
91-
['/a', 'm/*'],
92-
['a', 'a/b', 'a/b/c', 'm/'],
93-
['aa', 'm', 'b/m', 'b/m/'],
91+
['/a', 'm/*', 'o/**', 'p/**/', 'x**y'],
92+
['a', 'a/b', 'a/b/c', 'm/', 'o/', 'p/', 'xy', 'xuy', 'x/y', 'x/u/y', 'xu/y', 'x/uy', 'xu/uy'],
93+
['aa', 'm', 'b/m', 'b/m/', 'o', 'b/o', 'b/o/', 'p', 'b/p', 'b/p/'],
9494
],
9595
[
9696
['a', '!x'],
@@ -173,8 +173,8 @@ public function provider(): array
173173
],
174174
[
175175
['dir1/**/dir2/'],
176-
['dir1/dirA/dir2/', 'dir1/dirA/dirB/dir2/'],
177-
[],
176+
['dir1/dir2/', 'dir1/dirA/dir2/', 'dir1/dirA/dirB/dir2/'],
177+
['dir1dir2/', 'dir1xdir2/', 'dir1/xdir2/', 'dir1x/dir2/'],
178178
],
179179
[
180180
['dir1/*/dir2/'],
@@ -202,37 +202,22 @@ public function provider(): array
202202
['a/app/cache/file.txt'],
203203
],
204204
[
205-
[
206-
'#IamComment',
207-
'/app/cache/',
208-
],
205+
['#IamComment', '/app/cache/'],
209206
['app/cache/file.txt', 'app/cache/subdir/ile.txt'],
210207
['a/app/cache/file.txt', '#IamComment', 'IamComment'],
211208
],
212209
[
213-
[
214-
'/app/cache/',
215-
'#LastLineIsComment',
216-
],
210+
['/app/cache/', '#LastLineIsComment'],
217211
['app/cache/file.txt', 'app/cache/subdir/ile.txt'],
218212
['a/app/cache/file.txt', '#LastLineIsComment', 'LastLineIsComment'],
219213
],
220214
[
221-
[
222-
'/app/cache/',
223-
'\#file.txt',
224-
'#LastLineIsComment',
225-
],
215+
['/app/cache/', '\#file.txt', '#LastLineIsComment'],
226216
['app/cache/file.txt', 'app/cache/subdir/ile.txt', '#file.txt'],
227217
['a/app/cache/file.txt', '#LastLineIsComment', 'LastLineIsComment'],
228218
],
229219
[
230-
[
231-
'/app/cache/',
232-
'\#file.txt',
233-
'#IamComment',
234-
'another_file.txt',
235-
],
220+
['/app/cache/', '\#file.txt', '#IamComment', 'another_file.txt'],
236221
['app/cache/file.txt', 'app/cache/subdir/ile.txt', '#file.txt', 'another_file.txt'],
237222
['a/app/cache/file.txt', 'IamComment', '#IamComment'],
238223
],
@@ -280,6 +265,127 @@ public function provider(): array
280265
['example/test', 'example/example.txt2', 'example/packages/foo.yaml'],
281266
['example/example.txt', 'example/packages', 'example/packages/'],
282267
],
268+
// based on https://www.atlassian.com/git/tutorials/saving-changes/gitignore
269+
[
270+
['**/logs'],
271+
['logs/debug.log', 'logs/monday/foo.bar'],
272+
[],
273+
],
274+
[
275+
['**/logs/debug.log'],
276+
['logs/debug.log', 'build/logs/debug.log'],
277+
['logs/build/debug.log'],
278+
],
279+
[
280+
['*.log'],
281+
['debug.log', 'foo.log', '.log', 'logs/debug.log'],
282+
[],
283+
],
284+
[
285+
[
286+
'*.log',
287+
'!important.log',
288+
],
289+
['debug.log', 'trace.log'],
290+
['important.log', 'logs/important.log'],
291+
],
292+
[
293+
[
294+
'*.log',
295+
'!important/*.log',
296+
'trace.*',
297+
],
298+
['debug.log', 'important/trace.log'],
299+
['important/debug.log'],
300+
],
301+
[
302+
['/debug.log'],
303+
['debug.log'],
304+
['logs/debug.log'],
305+
],
306+
[
307+
['debug.log'],
308+
['debug.log', 'logs/debug.log'],
309+
[],
310+
],
311+
[
312+
['debug?.log'],
313+
['debug0.log', 'debugg.log'],
314+
['debug10.log'],
315+
],
316+
[
317+
['debug[0-9].log'],
318+
['debug0.log', 'debug1.log'],
319+
['debug10.log'],
320+
],
321+
[
322+
['debug[01].log'],
323+
['debug0.log', 'debug1.log'],
324+
['debug2.log', 'debug01.log'],
325+
],
326+
[
327+
['debug[!01].log'],
328+
['debug2.log'],
329+
['debug0.log', 'debug1.log', 'debug01.log'],
330+
],
331+
[
332+
['debug[a-z].log'],
333+
['debuga.log', 'debugb.log'],
334+
['debug1.log'],
335+
],
336+
[
337+
['logs'],
338+
['logs', 'logs/debug.log', 'logs/latest/foo.bar', 'build/logs', 'build/logs/debug.log'],
339+
[],
340+
],
341+
[
342+
['logs/'],
343+
['logs/debug.log', 'logs/latest/foo.bar', 'build/logs/foo.bar', 'build/logs/latest/debug.log'],
344+
[],
345+
],
346+
[
347+
[
348+
'logs/',
349+
'!logs/important.log',
350+
],
351+
['logs/debug.log'/* must be pruned on traversal 'logs/important.log'*/],
352+
[],
353+
],
354+
[
355+
['logs/**/debug.log'],
356+
['logs/debug.log', 'logs/monday/debug.log', 'logs/monday/pm/debug.log'],
357+
[],
358+
],
359+
[
360+
['logs/*day/debug.log'],
361+
['logs/monday/debug.log', 'logs/tuesday/debug.log'],
362+
['logs/latest/debug.log'],
363+
],
364+
[
365+
['logs/debug.log'],
366+
['logs/debug.log'],
367+
['debug.log', 'build/logs/debug.log'],
368+
],
369+
[
370+
['*/vendor/*'],
371+
AE87 ['a/vendor/', 'a/vendor/b', 'a/vendor/b/c'],
372+
['a', 'vendor', 'vendor/', 'a/vendor', 'a/b/vendor', 'a/b/vendor/c'],
373+
],
374+
[
375+
['**/vendor/**'],
376+
['vendor/', 'vendor/a', 'vendor/a/b', 'a/b/vendor/c/d'],
377+
['a', 'vendor', 'a/vendor', 'a/b/vendor'],
378+
],
379+
[
380+
['***/***/vendor/*****/*****'],
381+
['vendor/', 'vendor/a', 'vendor/a/b', 'a/b/vendor/c/d'],
382+
['a', 'vendor', 'a/vendor', 'a/b/vendor'],
383+
],
384+
[
385+
['**vendor**'],
386+
['vendor', 'vendor/', 'vendor/a', 'vendor/a/b', 'a/vendor', 'a/b/vendor', 'a/b/vendor/c/d'],
387+
['a'],
388+
],
283389
];
284390

285391
return $cases;

0 commit comments

Comments
 (0)
0