about summary refs log tree commit diff
path: root/src/libextra
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-10-16 11:26:35 -0700
committerbors <bors@rust-lang.org>2013-10-16 11:26:35 -0700
commit40180cdbea708307ca66dc6debddbd5ecc1ea41c (patch)
tree0d26ddfa020874dc3f665c2c1d3e836ee729408b /src/libextra
parentfabec998e5667d651d3475c12ee25ab97d21105c (diff)
parentd108a22fd1b38c108e2b9b6cd7276d953524ffa2 (diff)
downloadrust-40180cdbea708307ca66dc6debddbd5ecc1ea41c.tar.gz
rust-40180cdbea708307ca66dc6debddbd5ecc1ea41c.zip
auto merge of #9655 : kballard/rust/path-rewrite, r=alexcrichton
Rewrite the entire `std::path` module from scratch.

`PosixPath` is now based on `~[u8]`, which fixes #7225.
Unnecessary allocation has been eliminated.

There are a lot of clients of `Path` that still assume utf-8 paths.
This is covered in #9639.
Diffstat (limited to 'src/libextra')
-rw-r--r--src/libextra/fileinput.rs16
-rw-r--r--src/libextra/glob.rs84
-rw-r--r--src/libextra/tempfile.rs2
-rw-r--r--src/libextra/terminfo/searcher.rs42
-rw-r--r--src/libextra/test.rs12
-rw-r--r--src/libextra/workcache.rs17
6 files changed, 100 insertions, 73 deletions
diff --git a/src/libextra/fileinput.rs b/src/libextra/fileinput.rs
index bf3fe4b39b2..8f176d5ccea 100644
--- a/src/libextra/fileinput.rs
+++ b/src/libextra/fileinput.rs
@@ -358,11 +358,11 @@ instance. `stdin_hyphen` controls whether `-` represents `stdin` or
 a literal `-`.
 */
 pub fn make_path_option_vec(vec: &[~str], stdin_hyphen : bool) -> ~[Option<Path>] {
-    vec.iter().map(|str| {
-        if stdin_hyphen && "-" == *str {
+    vec.iter().map(|s| {
+        if stdin_hyphen && "-" == *s {
             None
         } else {
-            Some(Path(*str))
+            Some(Path::new(s.as_slice()))
         }
     }).collect()
 }
@@ -435,14 +435,14 @@ mod test {
     fn test_make_path_option_vec() {
         let strs = [~"some/path",
                     ~"some/other/path"];
-        let paths = ~[Some(Path("some/path")),
-                      Some(Path("some/other/path"))];
+        let paths = ~[Some(Path::new("some/path")),
+                      Some(Path::new("some/other/path"))];
 
         assert_eq!(make_path_option_vec(strs, true), paths.clone());
         assert_eq!(make_path_option_vec(strs, false), paths);
 
         assert_eq!(make_path_option_vec([~"-"], true), ~[None]);
-        assert_eq!(make_path_option_vec([~"-"], false), ~[Some(Path("-"))]);
+        assert_eq!(make_path_option_vec([~"-"], false), ~[Some(Path::new("-"))]);
     }
 
     #[test]
@@ -567,9 +567,9 @@ mod test {
     #[test]
     fn test_no_trailing_newline() {
         let f1 =
-            Some(Path("tmp/lib-fileinput-test-no-trailing-newline-1.tmp"));
+            Some(Path::new("tmp/lib-fileinput-test-no-trailing-newline-1.tmp"));
         let f2 =
-            Some(Path("tmp/lib-fileinput-test-no-trailing-newline-2.tmp"));
+            Some(Path::new("tmp/lib-fileinput-test-no-trailing-newline-2.tmp"));
 
         {
             let mut wr = file::open(f1.get_ref(), io::CreateOrTruncate,
diff --git a/src/libextra/glob.rs b/src/libextra/glob.rs
index 112ea142189..031545c1cd2 100644
--- a/src/libextra/glob.rs
+++ b/src/libextra/glob.rs
@@ -24,6 +24,7 @@
  */
 
 use std::{os, path};
+use std::path::is_sep;
 
 use sort;
 
@@ -35,7 +36,7 @@ pub struct GlobIterator {
     priv root: Path,
     priv dir_patterns: ~[Pattern],
     priv options: MatchOptions,
-    priv todo: ~[Path]
+    priv todo: ~[(Path,uint)]
 }
 
 /**
@@ -80,18 +81,28 @@ pub fn glob(pattern: &str) -> GlobIterator {
  * Paths are yielded in alphabetical order, as absolute paths.
  */
 pub fn glob_with(pattern: &str, options: MatchOptions) -> GlobIterator {
+    #[cfg(windows)]
+    fn check_windows_verbatim(p: &Path) -> bool { path::windows::is_verbatim(p) }
+    #[cfg(not(windows))]
+    fn check_windows_verbatim(_: &Path) -> bool { false }
+
+    // calculate root this way to handle volume-relative Windows paths correctly
+    let mut root = os::getcwd();
+    let pat_root = Path::new(pattern).root_path();
+    if pat_root.is_some() {
+        if check_windows_verbatim(pat_root.get_ref()) {
+            // XXX: How do we want to handle verbatim paths? I'm inclined to return nothing,
+            // since we can't very well find all UNC shares with a 1-letter server name.
+            return GlobIterator { root: root, dir_patterns: ~[], options: options, todo: ~[] };
+        }
+        root.push(pat_root.get_ref());
+    }
 
-    // note that this relies on the glob meta characters not
-    // having any special meaning in actual pathnames
-    let path = Path(pattern);
-    let dir_patterns = path.components.map(|s| Pattern::new(*s));
+    let root_len = pat_root.map_default(0u, |p| p.as_vec().len());
+    let dir_patterns = pattern.slice_from(root_len.min(&pattern.len()))
+                       .split_terminator_iter(is_sep).map(|s| Pattern::new(s)).to_owned_vec();
 
-    let root = if path.is_absolute() {
-        Path {components: ~[], .. path} // preserve windows path host/device
-    } else {
-        os::getcwd()
-    };
-    let todo = list_dir_sorted(&root);
+    let todo = list_dir_sorted(&root).move_iter().map(|x|(x,0u)).to_owned_vec();
 
     GlobIterator {
         root: root,
@@ -109,18 +120,24 @@ impl Iterator<Path> for GlobIterator {
                 return None;
             }
 
-            let path = self.todo.pop();
-            let pattern_index = path.components.len() - self.root.components.len() - 1;
-            let ref pattern = self.dir_patterns[pattern_index];
+            let (path,idx) = self.todo.pop();
+            let ref pattern = self.dir_patterns[idx];
 
-            if pattern.matches_with(*path.components.last(), self.options) {
-
-                if pattern_index == self.dir_patterns.len() - 1 {
+            if pattern.matches_with(match path.filename_str() {
+                // this ugly match needs to go here to avoid a borrowck error
+                None => {
+                    // FIXME (#9639): How do we handle non-utf8 filenames? Ignore them for now
+                    // Ideally we'd still match them against a *
+                    continue;
+                }
+                Some(x) => x
+            }, self.options) {
+                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);
                 } else {
-                    self.todo.push_all(list_dir_sorted(&path));
+                    self.todo.extend(&mut list_dir_sorted(&path).move_iter().map(|x|(x,idx+1)));
                 }
             }
         }
@@ -130,7 +147,7 @@ impl Iterator<Path> for GlobIterator {
 
 fn list_dir_sorted(path: &Path) -> ~[Path] {
     let mut children = os::list_dir_path(path);
-    sort::quick_sort(children, |p1, p2| p2.components.last() <= p1.components.last());
+    sort::quick_sort(children, |p1, p2| p2.filename().unwrap() <= p1.filename().unwrap());
     children
 }
 
@@ -285,7 +302,10 @@ impl Pattern {
      * using the default match options (i.e. `MatchOptions::new()`).
      */
     pub fn matches_path(&self, path: &Path) -> bool {
-        self.matches(path.to_str())
+        // FIXME (#9639): This needs to handle non-utf8 paths
+        do path.as_str().map_default(false) |s| {
+            self.matches(s)
+        }
     }
 
     /**
@@ -300,7 +320,10 @@ impl Pattern {
      * using the specified match options.
      */
     pub fn matches_path_with(&self, path: &Path, options: MatchOptions) -> bool {
-        self.matches_with(path.to_str(), options)
+        // FIXME (#9639): This needs to handle non-utf8 paths
+        do path.as_str().map_default(false) |s| {
+            self.matches_with(s, options)
+        }
     }
 
     fn matches_from(&self,
@@ -446,16 +469,6 @@ fn chars_eq(a: char, b: char, case_sensitive: bool) -> bool {
     }
 }
 
-/// A helper function to determine if a char is a path separator on the current platform.
-fn is_sep(c: char) -> bool {
-    if cfg!(windows) {
-        path::windows::is_sep(c)
-    } else {
-        path::posix::is_sep(c)
-    }
-}
-
-
 /**
  * Configuration options to modify the behaviour of `Pattern::matches_with(..)`
  */
@@ -522,8 +535,9 @@ mod test {
         assert!(glob("//").next().is_none());
 
         // check windows absolute paths with host/device components
-        let root_with_device = (Path {components: ~[], .. os::getcwd()}).to_str() + "*";
-        assert!(glob(root_with_device).next().is_some());
+        let root_with_device = os::getcwd().root_path().unwrap().join("*");
+        // FIXME (#9639): This needs to handle non-utf8 paths
+        assert!(glob(root_with_device.as_str().unwrap()).next().is_some());
     }
 
     #[test]
@@ -745,9 +759,9 @@ mod test {
 
     #[test]
     fn test_matches_path() {
-        // on windows, (Path("a/b").to_str() == "a\\b"), so this
+        // on windows, (Path::new("a/b").as_str().unwrap() == "a\\b"), so this
         // tests that / and \ are considered equivalent on windows
-        assert!(Pattern::new("a/b").matches_path(&Path("a/b")));
+        assert!(Pattern::new("a/b").matches_path(&Path::new("a/b")));
     }
 }
 
diff --git a/src/libextra/tempfile.rs b/src/libextra/tempfile.rs
index 60084faad98..d8fa130916a 100644
--- a/src/libextra/tempfile.rs
+++ b/src/libextra/tempfile.rs
@@ -35,7 +35,7 @@ impl TempDir {
 
         let mut r = rand::rng();
         for _ in range(0u, 1000) {
-            let p = tmpdir.push(r.gen_ascii_str(16) + suffix);
+            let p = tmpdir.join(r.gen_ascii_str(16) + suffix);
             if os::make_dir(&p, 0x1c0) { // 700
                 return Some(TempDir { path: Some(p) });
             }
diff --git a/src/libextra/terminfo/searcher.rs b/src/libextra/terminfo/searcher.rs
index 5c7efdb298f..ea7d20e096d 100644
--- a/src/libextra/terminfo/searcher.rs
+++ b/src/libextra/terminfo/searcher.rs
@@ -14,10 +14,9 @@
 use std::{os, str};
 use std::os::getenv;
 use std::io::{file_reader, Reader};
-use path = std::path::Path;
 
 /// Return path to database entry for `term`
-pub fn get_dbpath_for_term(term: &str) -> Option<~path> {
+pub fn get_dbpath_for_term(term: &str) -> Option<~Path> {
     if term.len() == 0 {
         return None;
     }
@@ -29,25 +28,26 @@ pub fn get_dbpath_for_term(term: &str) -> Option<~path> {
 
     // Find search directory
     match getenv("TERMINFO") {
-        Some(dir) => dirs_to_search.push(path(dir)),
+        Some(dir) => dirs_to_search.push(Path::new(dir)),
         None => {
             if homedir.is_some() {
-                dirs_to_search.push(homedir.unwrap().push(".terminfo")); // ncurses compatability
+                // ncurses compatability;
+                dirs_to_search.push(homedir.unwrap().join(".terminfo"))
             }
             match getenv("TERMINFO_DIRS") {
                 Some(dirs) => for i in dirs.split_iter(':') {
                     if i == "" {
-                        dirs_to_search.push(path("/usr/share/terminfo"));
+                        dirs_to_search.push(Path::new("/usr/share/terminfo"));
                     } else {
-                        dirs_to_search.push(path(i.to_owned()));
+                        dirs_to_search.push(Path::new(i.to_owned()));
                     }
                 },
                 // Found nothing, use the default paths
                 // /usr/share/terminfo is the de facto location, but it seems
                 // Ubuntu puts it in /lib/terminfo
                 None => {
-                    dirs_to_search.push(path("/usr/share/terminfo"));
-                    dirs_to_search.push(path("/lib/terminfo"));
+                    dirs_to_search.push(Path::new("/usr/share/terminfo"));
+                    dirs_to_search.push(Path::new("/lib/terminfo"));
                 }
             }
         }
@@ -55,14 +55,18 @@ pub fn get_dbpath_for_term(term: &str) -> Option<~path> {
 
     // Look for the terminal in all of the search directories
     for p in dirs_to_search.iter() {
-        let newp = ~p.push_many(&[str::from_char(first_char), term.to_owned()]);
-        if os::path_exists(p) && os::path_exists(newp) {
-            return Some(newp);
-        }
-        // on some installations the dir is named after the hex of the char (e.g. OS X)
-        let newp = ~p.push_many(&[format!("{:x}", first_char as uint), term.to_owned()]);
-        if os::path_exists(p) && os::path_exists(newp) {
-            return Some(newp);
+        if os::path_exists(p) {
+            let f = str::from_char(first_char);
+            let newp = p.join_many([f.as_slice(), term]);
+            if os::path_exists(&newp) {
+                return Some(~newp);
+            }
+            // on some installations the dir is named after the hex of the char (e.g. OS X)
+            let f = format!("{:x}", first_char as uint);
+            let newp = p.join_many([f.as_slice(), term]);
+            if os::path_exists(&newp) {
+                return Some(~newp);
+            }
         }
     }
     None
@@ -82,7 +86,11 @@ fn test_get_dbpath_for_term() {
     // woefully inadequate test coverage
     // note: current tests won't work with non-standard terminfo hierarchies (e.g. OS X's)
     use std::os::{setenv, unsetenv};
-    fn x(t: &str) -> ~str { get_dbpath_for_term(t).expect("no terminfo entry found").to_str() };
+    // FIXME (#9639): This needs to handle non-utf8 paths
+    fn x(t: &str) -> ~str {
+        let p = get_dbpath_for_term(t).expect("no terminfo entry found");
+        p.as_str().unwrap().to_owned()
+    };
     assert!(x("screen") == ~"/usr/share/terminfo/s/screen");
     assert!(get_dbpath_for_term("") == None);
     setenv("TERMINFO_DIRS", ":");
diff --git a/src/libextra/test.rs b/src/libextra/test.rs
index a352a2e4678..21fa9ed7574 100644
--- a/src/libextra/test.rs
+++ b/src/libextra/test.rs
@@ -271,20 +271,20 @@ pub fn parse_opts(args: &[~str]) -> Option<OptRes> {
     let run_ignored = matches.opt_present("ignored");
 
     let logfile = matches.opt_str("logfile");
-    let logfile = logfile.map(|s| Path(s));
+    let logfile = logfile.map(|s| Path::new(s));
 
     let run_benchmarks = matches.opt_present("bench");
     let run_tests = ! run_benchmarks ||
         matches.opt_present("test");
 
     let ratchet_metrics = matches.opt_str("ratchet-metrics");
-    let ratchet_metrics = ratchet_metrics.map(|s| Path(s));
+    let ratchet_metrics = ratchet_metrics.map(|s| Path::new(s));
 
     let ratchet_noise_percent = matches.opt_str("ratchet-noise-percent");
     let ratchet_noise_percent = ratchet_noise_percent.map(|s| from_str::<f64>(s).unwrap());
 
     let save_metrics = matches.opt_str("save-metrics");
-    let save_metrics = save_metrics.map(|s| Path(s));
+    let save_metrics = save_metrics.map(|s| Path::new(s));
 
     let test_shard = matches.opt_str("test-shard");
     let test_shard = opt_shard(test_shard);
@@ -547,7 +547,7 @@ impl ConsoleTestState {
         let ratchet_success = match *ratchet_metrics {
             None => true,
             Some(ref pth) => {
-                self.out.write_str(format!("\nusing metrics ratchet: {}\n", pth.to_str()));
+                self.out.write_str(format!("\nusing metrics ratchet: {}\n", pth.display()));
                 match ratchet_pct {
                     None => (),
                     Some(pct) =>
@@ -659,7 +659,7 @@ pub fn run_tests_console(opts: &TestOpts,
         None => (),
         Some(ref pth) => {
             st.metrics.save(pth);
-            st.out.write_str(format!("\nmetrics saved to: {}", pth.to_str()));
+            st.out.write_str(format!("\nmetrics saved to: {}", pth.display()));
         }
     }
     return st.write_run_finish(&opts.ratchet_metrics, opts.ratchet_noise_percent);
@@ -1440,7 +1440,7 @@ mod tests {
     pub fn ratchet_test() {
 
         let dpth = TempDir::new("test-ratchet").expect("missing test for ratchet");
-        let pth = dpth.path().push("ratchet.json");
+        let pth = dpth.path().join("ratchet.json");
 
         let mut m1 = MetricMap::new();
         m1.insert_metric("runtime", 1000.0, 2.0);
diff --git a/src/libextra/workcache.rs b/src/libextra/workcache.rs
index 32a2d83d814..26309cf3b37 100644
--- a/src/libextra/workcache.rs
+++ b/src/libextra/workcache.rs
@@ -184,11 +184,11 @@ impl Database {
         let f = io::file_reader(&self.db_filename);
         match f {
             Err(e) => fail2!("Couldn't load workcache database {}: {}",
-                            self.db_filename.to_str(), e.to_str()),
+                            self.db_filename.display(), e.to_str()),
             Ok(r) =>
                 match json::from_reader(r) {
                     Err(e) => fail2!("Couldn't parse workcache database (from file {}): {}",
-                                    self.db_filename.to_str(), e.to_str()),
+                                    self.db_filename.display(), e.to_str()),
                     Ok(r) => {
                         let mut decoder = json::Decoder(r);
                         self.db_cache = Decodable::decode(&mut decoder);
@@ -498,7 +498,7 @@ fn test() {
     // Create a path to a new file 'filename' in the directory in which
     // this test is running.
     fn make_path(filename: ~str) -> Path {
-        let pth = os::self_exe_path().expect("workcache::test failed").pop().push(filename);
+        let pth = os::self_exe_path().expect("workcache::test failed").with_filename(filename);
         if os::path_exists(&pth) {
             os::remove_file(&pth);
         }
@@ -522,15 +522,20 @@ fn test() {
         let subcx = cx.clone();
         let pth = pth.clone();
 
-        prep.declare_input("file", pth.to_str(), digest_file(&pth));
+        // FIXME (#9639): This needs to handle non-utf8 paths
+        prep.declare_input("file", pth.as_str().unwrap(), digest_file(&pth));
         do prep.exec |_exe| {
             let out = make_path(~"foo.o");
-            run::process_status("gcc", [pth.to_str(), ~"-o", out.to_str()]);
+            // FIXME (#9639): This needs to handle non-utf8 paths
+            run::process_status("gcc", [pth.as_str().unwrap().to_owned(),
+                                        ~"-o",
+                                        out.as_str().unwrap().to_owned()]);
 
             let _proof_of_concept = subcx.prep("subfn");
             // Could run sub-rules inside here.
 
-            out.to_str()
+            // FIXME (#9639): This needs to handle non-utf8 paths
+            out.as_str().unwrap().to_owned()
         }
     };