1#![deny(warnings, missing_docs)]
2
3use std::fs;
6use std::io;
7use std::path::{Path, PathBuf};
8
9pub fn mkdirp<P: AsRef<Path>>(path: P) -> io::Result<Option<PathBuf>> {
15 let path = path.as_ref();
16 if path == Path::new("") {
17 return Ok(None);
18 }
19
20 match fs::create_dir(path) {
21 Ok(()) => return Ok(Some(path.to_owned())),
22 Err(ref e) if e.kind() == io::ErrorKind::NotFound => {}
23 Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => return Ok(None),
24 Err(_) if path.is_dir() => return Ok(None),
25 Err(e) => return Err(e),
26 }
27 let created = match path.parent() {
28 Some(p) => mkdirp(p),
29 None => {
30 return Err(io::Error::new(
31 io::ErrorKind::Other,
32 "failed to create whole tree",
33 ))
34 }
35 };
36 match fs::create_dir(path) {
37 Ok(()) => created,
38 Err(_) if path.is_dir() => created,
39 Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => created,
40 Err(e) => Err(e),
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47 #[test]
48 fn return_dir() {
49 let mut dir = std::env::temp_dir();
50 dir.push("mkdirp-test");
51 let test_path = dir.clone();
52 fs::remove_dir_all(&test_path).ok();
53 fs::create_dir(&test_path).unwrap();
54 dir.push("nested-1");
55 let expected = dir.clone();
56 dir.push("nested-2");
57 dir.push("nested-3");
58 let ret = mkdirp(dir.as_path()).unwrap().unwrap();
59 fs::remove_dir_all(test_path).unwrap();
60 assert_eq!(ret, expected);
61 }
62
63 #[test]
64 fn noop() {
65 let dir = std::env::temp_dir();
66 let ret = mkdirp(dir.as_path()).unwrap();
67 assert_eq!(ret, None);
68 }
69}