Skip to content

Commit

Permalink
Keep track of absolute patterns, those that have to start with it (#301)
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Apr 12, 2022
1 parent d18ef14 commit 3956480
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 9 deletions.
6 changes: 5 additions & 1 deletion git-attributes/tests/parse/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ fn line_numbers_are_counted_correctly() {
),
(pattern(r"!foo.html", Mode::NO_SUB_DIR, None), vec![set("x")], 8),
(pattern(r"#a/path", Mode::empty(), None), vec![unset("a")], 10),
(pattern(r"/*", Mode::empty(), Some(1)), vec![unspecified("b")], 11),
(
pattern(r"*", Mode::ABSOLUTE | Mode::NO_SUB_DIR | Mode::ENDS_WITH, Some(0)),
vec![unspecified("b")],
11
),
]
);
}
Expand Down
8 changes: 4 additions & 4 deletions git-attributes/tests/parse/ignore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ fn line_numbers_are_counted_correctly() {
("*.[oa]".into(), Mode::NO_SUB_DIR, 2),
("*.html".into(), Mode::NO_SUB_DIR | Mode::ENDS_WITH, 5),
("foo.html".into(), Mode::NO_SUB_DIR | Mode::NEGATIVE, 8),
("/*".into(), Mode::empty(), 11),
("/foo".into(), Mode::NEGATIVE, 12),
("/foo/*".into(), Mode::empty(), 13),
("/foo/bar".into(), Mode::NEGATIVE, 14)
("*".into(), Mode::NO_SUB_DIR | Mode::ENDS_WITH | Mode::ABSOLUTE, 11),
("foo".into(), Mode::NEGATIVE | Mode::NO_SUB_DIR | Mode::ABSOLUTE, 12),
("foo/*".into(), Mode::ABSOLUTE, 13),
("foo/bar".into(), Mode::ABSOLUTE | Mode::NEGATIVE, 14)
]
);
}
Expand Down
4 changes: 4 additions & 0 deletions git-glob/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ pub fn pattern(mut pat: &[u8]) -> Option<(BString, pattern::Mode, Option<usize>)
if pat.iter().all(|b| b.is_ascii_whitespace()) {
return None;
}
if pat.first() == Some(&b'/') {
mode |= Mode::ABSOLUTE;
pat = &pat[1..];
}
let mut line = truncate_non_escaped_trailing_spaces(pat);
if line.last() == Some(&b'/') {
mode |= Mode::MUST_BE_DIR;
Expand Down
10 changes: 8 additions & 2 deletions git-glob/src/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ bitflags! {
const MUST_BE_DIR = 1 << 2;
/// The pattern matches, but should be negated. Note that this mode has to be checked and applied by the caller.
const NEGATIVE = 1 << 3;
/// The pattern starts with a slash and thus matches only from the beginning.
const ABSOLUTE = 1 << 4;
}
}
bitflags! {
Expand Down Expand Up @@ -46,9 +48,13 @@ impl Pattern {
self.mode.contains(Mode::NEGATIVE)
}

/// Match the given `path` which takes slashes (and only slashes) literally.
/// Match the given `path` which takes slashes (and only slashes) literally, and is relative to the repository root.
/// Note that `path` is assumed to be sharing the base with the pattern already so they can be reasonably compared.
///
/// We may take various shortcuts which is when `basename_start_pos` and `is_dir` come into play.
/// Lastly, case insensitive matches are supported as well.
/// `basename_start_pos` is the index at which the `path`'s basename starts.
///
/// Lastly, `case` folding can be configured as well.
pub fn matches_path<'a>(
&self,
path: impl Into<&'a BStr>,
Expand Down
13 changes: 11 additions & 2 deletions git-glob/tests/matching/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ fn non_dirs_for_must_be_dir_patterns_are_ignored() {
}

#[test]
fn case_insensitive() {
fn basename_case_insensitive() {
let pattern = pat("foo");
assert!(pattern.matches_path("FoO", None, false, Case::Fold));
assert!(!pattern.matches_path("FoOo", None, false, Case::Fold));
Expand All @@ -109,7 +109,16 @@ fn case_insensitive() {
}

#[test]
fn glob_and_literal_is_ends_with() {
fn absolute_basename_matches_only_from_beginning() {
let pattern = pat("/foo");
assert!(pattern.matches_path("FoO", None, false, Case::Fold));
assert!(!pattern.matches_path("bar/Foo", None, false, Case::Fold));
assert!(pattern.matches_path("foo", None, false, Case::Sensitive));
assert!(!pattern.matches_path("bar/foo", None, false, Case::Sensitive));
}

#[test]
fn basename_glob_and_literal_is_ends_with() {
let pattern = pat("*foo");
assert!(pattern.matches_path("FoO", None, false, Case::Fold));
assert!(pattern.matches_path("BarFoO", None, false, Case::Fold));
Expand Down
13 changes: 13 additions & 0 deletions git-glob/tests/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,19 @@ fn leading_exclamation_marks_can_be_escaped_with_backslash() {
);
}

#[test]
fn leading_slashes_mark_patterns_as_absolute() {
assert_eq!(
git_glob::parse(br"/absolute"),
Some(("absolute".into(), Mode::NO_SUB_DIR | Mode::ABSOLUTE, None))
);

assert_eq!(
git_glob::parse(br"/absolute/path"),
Some(("absolute/path".into(), Mode::ABSOLUTE, None))
);
}

#[test]
fn absence_of_sub_directories_are_marked() {
assert_eq!(git_glob::parse(br"a/b"), Some(("a/b".into(), Mode::empty(), None)));
Expand Down

0 comments on commit 3956480

Please sign in to comment.