Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5bae7c6

Browse files
committed
attr_file: convert to use wildmatch
Upstream git has converted to use `wildmatch` instead of `fnmatch`. Convert our gitattributes logic to use `wildmatch` as the last user of `fnmatch`. Please, don't expect I know what I'm doing here: the fnmatch parser is one of the most fun things to play around with as it has a sh*tload of weird cases. In all honesty, I'm simply relying on our tests that are by now rather comprehensive in that area. The conversion actually fixes compatibility with how git.git parser "**" patterns when the given path does not contain any directory separators. Previously, a pattern "**.foo" erroneously wouldn't match a file "x.foo", while git.git would match. Remove the new-unused LEADINGDIR/NOLEADINGDIR flags for `git_attr_fnmatch`.
1 parent 1db591f commit 5bae7c6

File tree

5 files changed

+30
-31
lines changed

5 files changed

+30
-31
lines changed

src/attr_file.c

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
#include "git2/tree.h"
1616
#include "blob.h"
1717
#include "index.h"
18-
#include "fnmatch.h"
18+
#include "wildmatch.h"
1919
#include <ctype.h>
2020

2121
static void attr_file_free(git_attr_file *file)
@@ -402,18 +402,13 @@ bool git_attr_fnmatch__match(
402402
}
403403

404404
if (match->flags & GIT_ATTR_FNMATCH_ICASE)
405-
flags |= FNM_CASEFOLD;
406-
if (match->flags & GIT_ATTR_FNMATCH_LEADINGDIR)
407-
flags |= FNM_LEADING_DIR;
405+
flags |= WM_CASEFOLD;
408406

409407
if (match->flags & GIT_ATTR_FNMATCH_FULLPATH) {
410408
filename = relpath;
411-
flags |= FNM_PATHNAME;
409+
flags |= WM_PATHNAME;
412410
} else {
413411
filename = path->basename;
414-
415-
if (path->is_dir)
416-
flags |= FNM_LEADING_DIR;
417412
}
418413

419414
if ((match->flags & GIT_ATTR_FNMATCH_DIRECTORY) && !path->is_dir) {
@@ -428,8 +423,6 @@ bool git_attr_fnmatch__match(
428423
path->basename == relpath)
429424
return false;
430425

431-
flags |= FNM_LEADING_DIR;
432-
433426
/* fail match if this is a file with same name as ignored folder */
434427
samename = (match->flags & GIT_ATTR_FNMATCH_ICASE) ?
435428
!strcasecmp(match->pattern, relpath) :
@@ -438,10 +431,10 @@ bool git_attr_fnmatch__match(
438431
if (samename)
439432
return false;
440433

441-
return (p_fnmatch(match->pattern, relpath, flags) != FNM_NOMATCH);
434+
return (wildmatch(match->pattern, relpath, flags) == WM_MATCH);
442435
}
443436

444-
return (p_fnmatch(match->pattern, filename, flags) != FNM_NOMATCH);
437+
return (wildmatch(match->pattern, filename, flags) == WM_MATCH);
445438
}
446439

447440
bool git_attr_rule__match(
@@ -659,8 +652,6 @@ int git_attr_fnmatch__parse(
659652

660653
if (*pattern == '!' && (spec->flags & GIT_ATTR_FNMATCH_ALLOWNEG) != 0) {
661654
spec->flags = spec->flags | GIT_ATTR_FNMATCH_NEGATIVE;
662-
if ((spec->flags & GIT_ATTR_FNMATCH_NOLEADINGDIR) == 0)
663-
spec->flags |= GIT_ATTR_FNMATCH_LEADINGDIR;
664655
pattern++;
665656
}
666657

@@ -716,14 +707,6 @@ int git_attr_fnmatch__parse(
716707
if (--slash_count <= 0)
717708
spec->flags = spec->flags & ~GIT_ATTR_FNMATCH_FULLPATH;
718709
}
719-
if ((spec->flags & GIT_ATTR_FNMATCH_NOLEADINGDIR) == 0 &&
720-
spec->length >= 2 &&
721-
pattern[spec->length - 1] == '*' &&
722-
pattern[spec->length - 2] == '/') {
723-
spec->length -= 2;
724-
spec->flags = spec->flags | GIT_ATTR_FNMATCH_LEADINGDIR;
725-
/* leave FULLPATH match on, however */
726-
}
727710

728711
if (context) {
729712
char *slash = strrchr(context, '/');

src/attr_file.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,9 @@
3232
#define GIT_ATTR_FNMATCH_MATCH_ALL (1U << 8)
3333
#define GIT_ATTR_FNMATCH_ALLOWNEG (1U << 9)
3434
#define GIT_ATTR_FNMATCH_ALLOWMACRO (1U << 10)
35-
#define GIT_ATTR_FNMATCH_LEADINGDIR (1U << 11)
36-
#define GIT_ATTR_FNMATCH_NOLEADINGDIR (1U << 12)
3735

3836
#define GIT_ATTR_FNMATCH__INCOMING \
39-
(GIT_ATTR_FNMATCH_ALLOWSPACE | GIT_ATTR_FNMATCH_ALLOWNEG | \
40-
GIT_ATTR_FNMATCH_ALLOWMACRO | GIT_ATTR_FNMATCH_NOLEADINGDIR)
37+
(GIT_ATTR_FNMATCH_ALLOWSPACE | GIT_ATTR_FNMATCH_ALLOWNEG | GIT_ATTR_FNMATCH_ALLOWMACRO)
4138

4239
typedef enum {
4340
GIT_ATTR_FILE__IN_MEMORY = 0,

src/ignore.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,7 @@ static int parse_ignore_file(
193193
}
194194

195195
match->flags =
196-
GIT_ATTR_FNMATCH_ALLOWSPACE |
197-
GIT_ATTR_FNMATCH_ALLOWNEG |
198-
GIT_ATTR_FNMATCH_NOLEADINGDIR;
196+
GIT_ATTR_FNMATCH_ALLOWSPACE | GIT_ATTR_FNMATCH_ALLOWNEG;
199197

200198
if (!(error = git_attr_fnmatch__parse(
201199
match, &attrs->pool, context, &scan)))

src/pathspec.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,7 @@ int git_pathspec__vinit(
8585
if (!match)
8686
return -1;
8787

88-
match->flags = GIT_ATTR_FNMATCH_ALLOWSPACE |
89-
GIT_ATTR_FNMATCH_ALLOWNEG | GIT_ATTR_FNMATCH_NOLEADINGDIR;
88+
match->flags = GIT_ATTR_FNMATCH_ALLOWSPACE | GIT_ATTR_FNMATCH_ALLOWNEG;
9089

9190
ret = git_attr_fnmatch__parse(match, strpool, NULL, &pattern);
9291
if (ret == GIT_ENOTFOUND) {

tests/ignore/path.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,28 @@ void test_ignore_path__globs_and_path_delimiters(void)
230230
assert_is_ignored(false, "_test/foo/bar/code/file");
231231
}
232232

233+
void test_ignore_path__globs_without_star(void)
234+
{
235+
cl_git_rewritefile(
236+
"attr/.gitignore",
237+
"*.foo\n"
238+
"**.bar\n"
239+
);
240+
241+
assert_is_ignored(true, ".foo");
242+
assert_is_ignored(true, "xyz.foo");
243+
assert_is_ignored(true, ".bar");
244+
assert_is_ignored(true, "x.bar");
245+
assert_is_ignored(true, "xyz.bar");
246+
247+
assert_is_ignored(true, "test/.foo");
248+
assert_is_ignored(true, "test/x.foo");
249+
assert_is_ignored(true, "test/xyz.foo");
250+
assert_is_ignored(true, "test/.bar");
251+
assert_is_ignored(true, "test/x.bar");
252+
assert_is_ignored(true, "test/xyz.bar");
253+
}
254+
233255
void test_ignore_path__skip_gitignore_directory(void)
234256
{
235257
cl_git_rewritefile("attr/.git/info/exclude", "/NewFolder\n/NewFolder/NewFolder");

0 commit comments

Comments
 (0)