1use std::ffi::OsString;
7use std::fs::read_dir;
8use std::path::PathBuf;
9use std::{env, io};
10use std::io::ErrorKind;
11
12pub fn get_project_root() -> io::Result<PathBuf> {
20 let path = env::current_dir()?;
21 let mut path_ancestors = path.as_path().ancestors();
22
23 while let Some(p) = path_ancestors.next() {
24 let has_cargo =
25 read_dir(p)?
26 .into_iter()
27 .any(|p| p.unwrap().file_name() == OsString::from("Cargo.lock"));
28 if has_cargo {
29 return Ok(PathBuf::from(p))
30 }
31 }
32 Err(io::Error::new(ErrorKind::NotFound, "Ran out of places to find Cargo.toml"))
33
34}
35
36#[cfg(test)]
37mod tests {
38 use crate::get_project_root;
39 use std::fs::read_to_string;
40
41 #[test]
42 fn it_should_find_our_project_root() {
43 let crate_name = "name = \"project-root\"";
44
45 let project_root = get_project_root().expect("There is no project root");
46
47 let toml_path = project_root.to_str().unwrap().to_owned() + "/Cargo.toml";
48 let toml_string = read_to_string(toml_path).unwrap();
49
50 assert!(toml_string.contains(crate_name));
51 }
52}