about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBenjamin Herr <ben@0x539.de>2014-04-07 18:24:06 +0200
committerBenjamin Herr <ben@0x539.de>2014-04-08 01:21:37 +0200
commit1700f359bc5d6b8086194e3cc0f3698666dd41a4 (patch)
tree1b13a272ce86db854784afb66d615a4f8aa92efd
parent4051bd900abbb47557dd8928532eedbc2bca0563 (diff)
downloadrust-1700f359bc5d6b8086194e3cc0f3698666dd41a4.tar.gz
rust-1700f359bc5d6b8086194e3cc0f3698666dd41a4.zip
libglob: only return dirs for globs ending in /
`foo.txt/` should not return `foo.txt` if `foo.txt` is in fact a text
file and not a directory.
-rw-r--r--src/libglob/lib.rs14
-rw-r--r--src/test/run-pass/glob-std.rs2
2 files changed, 14 insertions, 2 deletions
diff --git a/src/libglob/lib.rs b/src/libglob/lib.rs
index 07b7c6604e7..d19924da5be 100644
--- a/src/libglob/lib.rs
+++ b/src/libglob/lib.rs
@@ -43,6 +43,7 @@ use std::path::is_sep;
 pub struct Paths {
     root: Path,
     dir_patterns: Vec<Pattern>,
+    require_dir: bool,
     options: MatchOptions,
     todo: Vec<(Path,uint)>,
 }
@@ -106,6 +107,7 @@ pub fn glob_with(pattern: &str, options: MatchOptions) -> Paths {
             return Paths {
                 root: root,
                 dir_patterns: Vec::new(),
+                require_dir: false,
                 options: options,
                 todo: Vec::new(),
             };
@@ -118,6 +120,7 @@ pub fn glob_with(pattern: &str, options: MatchOptions) -> Paths {
                        .split_terminator(is_sep)
                        .map(|s| Pattern::new(s))
                        .collect::<Vec<Pattern>>();
+    let require_dir = pattern.chars().next_back().map(is_sep) == Some(true);
 
     let mut todo = Vec::new();
     if dir_patterns.len() > 0 {
@@ -130,6 +133,7 @@ pub fn glob_with(pattern: &str, options: MatchOptions) -> Paths {
     Paths {
         root: root,
         dir_patterns: dir_patterns,
+        require_dir: require_dir,
         options: options,
         todo: todo,
     }
@@ -146,7 +150,10 @@ impl Iterator<Path> for Paths {
             let (path,idx) = self.todo.pop().unwrap();
             // idx -1: was already checked by fill_todo, maybe path was '.' or
             // '..' that we can't match here because of normalization.
-            if idx == -1 as uint { return Some(path); }
+            if idx == -1 as uint {
+                if self.require_dir && !path.is_dir() { continue; }
+                return Some(path);
+            }
             let ref pattern = *self.dir_patterns.get(idx);
 
             if pattern.matches_with(match path.filename_str() {
@@ -161,7 +168,10 @@ impl Iterator<Path> for Paths {
                 if idx == self.dir_patterns.len() - 1 {
                     // it is not possible for a pattern to match a directory *AND* its children
                     // so we don't need to check the children
-                    return Some(path);
+
+                    if !self.require_dir || path.is_dir() {
+                        return Some(path);
+                    }
                 } else {
                     fill_todo(&mut self.todo, self.dir_patterns.as_slice(),
                               idx + 1, &path, self.options);
diff --git a/src/test/run-pass/glob-std.rs b/src/test/run-pass/glob-std.rs
index eec6d675295..bd6161dd31a 100644
--- a/src/test/run-pass/glob-std.rs
+++ b/src/test/run-pass/glob-std.rs
@@ -138,6 +138,8 @@ pub fn main() {
     assert_eq!(glob_vec("nonexistent/../bbb"), Vec::new());
     assert_eq!(glob_vec("aaa/tomato/tomato.txt/.."), Vec::new());
 
+    assert_eq!(glob_vec("aaa/tomato/tomato.txt/"), Vec::new());
+
     assert_eq!(glob_vec("aa[a]"), vec!(abs_path("aaa")));
     assert_eq!(glob_vec("aa[abc]"), vec!(abs_path("aaa")));
     assert_eq!(glob_vec("a[bca]a"), vec!(abs_path("aaa")));