Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,10 @@ fn fill_todo(
};

let pattern = &patterns[idx];
// Whether this component's pattern starts with a literal `.`, in which case
// it is allowed to match entries whose name starts with a `.` even when
// `require_literal_leading_dot` is set.
let has_literal_leading_dot = matches!(pattern.tokens.first(), Some(Char('.')));
let is_dir = path.is_directory;
let curdir = path.as_ref() == Path::new(".");
match (pattern.has_metachars, is_dir) {
Expand Down Expand Up @@ -960,7 +964,15 @@ fn fill_todo(
});
match dirs {
Ok(mut children) => {
if options.require_literal_leading_dot {
// Entries whose name starts with a `.` are skipped here so
// that a recursive `**` component, which matches directory
// entries without ever consulting the pattern, does not
// descend into them. Patterns that do start with a literal
// `.` must not be filtered: `Pattern::matches_with` already
// implements `require_literal_leading_dot` faithfully for
// them, and dropping the entries here would make e.g.
// `.git*` match nothing at all.
if options.require_literal_leading_dot && !has_literal_leading_dot {
children.retain(|x| !x.1.to_str().unwrap().starts_with('.'));
}
children.sort_by(|p1, p2| p2.1.cmp(&p1.1));
Expand All @@ -971,7 +983,7 @@ fn fill_todo(
// requires that the pattern has a leading dot, even if the
// `MatchOptions` field `require_literal_leading_dot` is not
// set.
if !pattern.tokens.is_empty() && pattern.tokens[0] == Char('.') {
if has_literal_leading_dot {
for &special in &[".", ".."] {
if pattern.matches_with(special, options) {
add(todo, PathWrapper::from_path(path.join(special)));
Expand Down
25 changes: 25 additions & 0 deletions tests/glob-std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,31 @@ fn main() {
vec!(PathBuf::from("i/qwe"), PathBuf::from("i/qwe/eee"))
);

// `require_literal_leading_dot` only requires that the leading `.` appears
// literally in the pattern -- it must not stop such a pattern from matching.
// This mirrors what `Pattern::matches_with` does for the same options.
mk_file("j", true);
mk_file("j/.aaa", false);
mk_file("j/.abb", false);
mk_file("j/bbb", false);

assert_eq!(
glob_with_vec("j/.a*", options),
vec!(PathBuf::from("j/.aaa"), PathBuf::from("j/.abb"))
);
assert_eq!(
glob_with_vec("j/.?aa", options),
vec!(PathBuf::from("j/.aaa"))
);
assert_eq!(
glob_with_vec("j/.[ab]bb", options),
vec!(PathBuf::from("j/.abb"))
);
// ... while patterns that do not start with a literal `.` keep skipping
// those entries.
assert_eq!(glob_with_vec("j/*", options), vec!(PathBuf::from("j/bbb")));
assert_eq!(glob_with_vec("j/?aa", options), Vec::<PathBuf>::new());

if env::consts::FAMILY != "windows" {
assert_eq!(
glob_vec("bbb/specials/[*]"),
Expand Down