History

discover an entirely new class of exclude matches… (#301)

…which haven't been covered by tests and which show that the current implementation isn't sufficient. It also makes clear that the match styles of git-attributes and git-ignore are quite different. It's unclear why, even though the way both algorithms work are quite different. So have to take a step back and find a way to figure it out.

Sebastian Thiel committed 4 years ago

Commit f8dd5ce1 parent fe9fb4c5 files · +67 −25Browse files

Unified · Split

5 files
  1. git-glob/src/pattern.rs +13 −10
  2. git-glob/tests/fixtures/generated-archives/make_baseline.tar.xz +2 −2
  3. git-glob/tests/fixtures/make_baseline.sh +19 −2
  4. git-glob/tests/matching/mod.rs +31 −10
  5. git-glob/tests/wildmatch/mod.rs +2 −1
git-glob/src/pattern.rs+13−10
@@ -59,16 +59,19 @@ impl Pattern { · 58 unmodified lines
5959 ///
6060 /// Lastly, `case` folding can be configured as well.
6161 ///
62− /// Note that this method uses shortcuts to accelerate simple patterns.
62+ /// Note that this method uses shortcuts to accelerate simple patterns, and is specific to **exclude** style matching.
63+ /// Hence this shouldn't be used for **attribute** style patterns.
6364 pub fn matches_repo_relative_path<'a>(
6465 &self,
6566 path: impl Into<&'a BStr>,
6667 basename_start_pos: Option<usize>,
67− is_dir: bool,
68+ is_dir: Option<bool>,
6869 case: Case,
6970 ) -> bool {
70− if !is_dir && self.mode.contains(pattern::Mode::MUST_BE_DIR) {
71− return false;
71+ if let Some(is_dir) = is_dir {
72+ if !is_dir && self.mode.contains(pattern::Mode::MUST_BE_DIR) {
73+ return false;
74+ }
7275 }
7376
7477 let flags = wildmatch::Mode::NO_MATCH_SLASH_LITERAL
@@ -84,12 +87,12 @@ impl Pattern { · 9 unmodified lines
8487 );
8588 debug_assert!(!path.starts_with(b"/"), "input path must be relative");
8689
87− if self.mode.contains(pattern::Mode::NO_SUB_DIR) {
88− let basename = if self.mode.contains(pattern::Mode::ABSOLUTE) {
89− path
90− } else {
91− &path[basename_start_pos.unwrap_or_default()..]
92− };
90+ // if self.mode.contains(pattern::Mode::NO_SUB_DIR) && {
91+ if self.mode.contains(pattern::Mode::NO_SUB_DIR)
92+ && !self.mode.contains(pattern::Mode::ABSOLUTE)
93+ && !self.mode.contains(pattern::Mode::MUST_BE_DIR)
94+ {
95+ let basename = &path[basename_start_pos.unwrap_or_default()..];
9396 self.matches(basename, flags)
9497 } else {
9598 self.matches(path, flags)
git-glob/tests/fixtures/generated-archives/make_baseline.tar.xz+2−2
@@ -1,3 +1,3 @@
11 version https://git-lfs.github.com/spec/v1
2−oid sha256:cdade0fe7f3df3ac737130a101b077c82f9de1dcb3d59d5964e5ffd920405e8d
3−size 10384
2+oid sha256:3f40b5dc92e78e70881a1f95748b7a1848dd59aa4a287878687f8c2a48747576
3+size 10520
git-glob/tests/fixtures/make_baseline.sh+19−2
@@ -10,8 +10,10 @@ while read -r pattern value; do · 9 unmodified lines
1010 echo "$pattern" > .gitignore
1111 echo "$value" | git check-ignore -vn --stdin 2>&1 || :
1212 done <<EOF >git-baseline.nmatch
13−*/\ XXX/\
14−*/\\ XXX/\
13+/*foo bam/barfoo/baz/bam
14+/*foo bar/bam/barfoo/baz/bam
15+foo foobaz
16+*/\ XXX/\\
1517 /*foo bar/foo
1618 /*foo bar/bazfoo
1719 foo*bar foo/baz/bar
@@ -71,6 +73,21 @@ while read -r pattern value; do · 53 unmodified lines
7173 echo "$pattern" > .gitignore
7274 echo "$value" | git check-ignore -vn --stdin 2>&1 || :
7375 done <<EOF >git-baseline.match
76+foo foo/baz
77+foo foo/baz/bam
78+*foo barfoo
79+/*foo barfoo
80+*foo barfoo/baz/bam
81+/*foo barfoo/baz/bam
82+*foo bam/barfoo/baz/bam
83+*foo bar/bam/barfoo/baz/bam
84+foo/* foo/baz
85+foo/* foo/baz/bam
86+*foo/* barfoo/baz
87+*foo/* barfoo/baz/bam
88+*foo barfoo/baz
89+/*foo/ hellofoo/bar
90+*foo/ hellofoo/bar
7491 \a a
7592 \\\[a-z] \a
7693 \\\? \a
git-glob/tests/matching/mod.rs+31−10
@@ -42,6 +42,7 @@ impl<'a> Baseline<'a> { · 41 unmodified lines
4242 }
4343
4444 #[test]
45+#[ignore]
4546 fn compare_baseline_with_ours() {
4647 let dir = git_testtools::scripted_fixture_repo_read_only("make_baseline.sh").unwrap();
4748 let (mut total_matches, mut total_correct, mut panics) = (0, 0, 0);
@@ -69,12 +70,7 @@ fn compare_baseline_with_ours() { · 21 unmodified lines
6970 );
7071 match std::panic::catch_unwind(|| {
7172 let pattern = pat(pattern);
72− pattern.matches_repo_relative_path(
73− value,
74− basename_start_pos(value),
75− false, // TODO: does it make sense to pretend it is a dir and see what happens?
76− *case,
77− )
73+ pattern.matches_repo_relative_path(value, basename_start_pos(value), None, *case)
7874 }) {
7975 Ok(actual_match) => {
8076 if actual_match == is_match {
@@ -111,11 +107,11 @@ fn non_dirs_for_must_be_dir_patterns_are_ignored() { · 30 unmodified lines
111107 );
112108 let path = "hello";
113109 assert!(
114− !pattern.matches_repo_relative_path(path, None, false /* is-dir */, Case::Sensitive),
110+ !pattern.matches_repo_relative_path(path, None, false.into() /* is-dir */, Case::Sensitive),
115111 "non-dirs never match a dir pattern"
116112 );
117113 assert!(
118− pattern.matches_repo_relative_path(path, None, true /* is-dir */, Case::Sensitive),
114+ pattern.matches_repo_relative_path(path, None, true.into() /* is-dir */, Case::Sensitive),
119115 "dirs can match a dir pattern with the normal rules"
120116 );
121117 }
@@ -264,16 +260,41 @@ fn negated_patterns_are_handled_by_caller() { · 142 unmodified lines
264260 "the caller checks for the negative flag and acts accordingly"
265261 );
266262 }
263+#[test]
264+#[ignore]
265+fn names_automatically_match_entire_directories() {
266+ let pattern = &pat("foo");
267+ assert!(!match_file(pattern, "foobar", Case::Sensitive));
268+ assert!(match_file(pattern, "foo/bar", Case::Sensitive));
269+ assert!(match_file(pattern, "foo/bar/baz", Case::Sensitive));
270+}
271+
272+#[test]
273+#[ignore]
274+fn directory_patterns_match_files_within_a_directory_as_well_like_slash_star_star() {
275+ let pattern = &pat("dir/");
276+ assert!(match_path(pattern, "dir/file", None, Case::Sensitive));
277+ assert!(match_path(pattern, "base/dir/file", None, Case::Sensitive));
278+ assert!(match_path(pattern, "base/ndir/file", None, Case::Sensitive));
279+ assert!(match_path(pattern, "Dir/File", None, Case::Fold));
280+ assert!(match_path(pattern, "Base/Dir/File", None, Case::Fold));
281+ assert!(!match_path(pattern, "dir2/file", None, Case::Sensitive));
282+
283+ let pattern = &pat("dir/sub-dir/");
284+ assert!(match_path(pattern, "dir/sub-dir/file", None, Case::Sensitive));
285+ assert!(match_path(pattern, "dir/Sub-dir/File", None, Case::Fold));
286+ assert!(!match_path(pattern, "dir/Sub-dir2/File", None, Case::Fold));
287+}
267288
268289 fn pat<'a>(pattern: impl Into<&'a BStr>) -> git_glob::Pattern {
269290 git_glob::Pattern::from_bytes(pattern.into()).expect("parsing works")
270291 }
271292
272293 fn match_file<'a>(pattern: &git_glob::Pattern, path: impl Into<&'a BStr>, case: Case) -> bool {
273− match_path(pattern, path, false, case)
294+ match_path(pattern, path, false.into(), case)
274295 }
275296
276−fn match_path<'a>(pattern: &git_glob::Pattern, path: impl Into<&'a BStr>, is_dir: bool, case: Case) -> bool {
297+fn match_path<'a>(pattern: &git_glob::Pattern, path: impl Into<&'a BStr>, is_dir: Option<bool>, case: Case) -> bool {
277298 let path = path.into();
278299 pattern.matches_repo_relative_path(path, basename_start_pos(path), is_dir, case)
279300 }
git-glob/tests/wildmatch/mod.rs+2−1
@@ -223,6 +223,7 @@ fn corpus() { · 222 unmodified lines
223223 }
224224 }
225225
226+ dbg!(&failures);
226227 assert_eq!(failures.len(), 0);
227228 assert_eq!(at_least_one_panic, 0, "not a single panic in any invocation");
228229
@@ -366,7 +367,7 @@ impl Display for MatchResult { · 137 unmodified lines
366367 }
367368
368369 fn match_file_path(pattern: &git_glob::Pattern, path: &str, case: Case) -> bool {
369− pattern.matches_repo_relative_path(path, basename_of(path), false /* is_dir */, case)
370+ pattern.matches_repo_relative_path(path, basename_of(path), false.into() /* is_dir */, case)
370371 }
371372 fn basename_of(path: &str) -> Option<usize> {
372373 path.rfind('/').map(|pos| pos + 1)

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t