1use std::path::{Path, PathBuf};
9
10#[must_use]
13pub fn detect_project_root(cwd: &Path) -> Option<PathBuf> {
14 let mut cur: Option<&Path> = Some(cwd);
15 let mut nearest_cargo: Option<PathBuf> = None;
16 while let Some(dir) = cur {
17 if dir.join(".git").exists() {
18 return Some(dir.to_path_buf());
19 }
20 if dir.join(".ready-set.toml").exists() {
21 return Some(dir.to_path_buf());
22 }
23 if nearest_cargo.is_none() && dir.join("Cargo.toml").exists() {
24 nearest_cargo = Some(dir.to_path_buf());
25 }
26 cur = dir.parent();
27 }
28 nearest_cargo
29}
30
31#[cfg(test)]
32mod tests {
33 use super::*;
34
35 #[test]
36 fn finds_git_root() {
37 let dir = tempfile::tempdir().unwrap();
38 std::fs::create_dir_all(dir.path().join(".git")).unwrap();
39 let inner = dir.path().join("a/b/c");
40 std::fs::create_dir_all(&inner).unwrap();
41 let root = detect_project_root(&inner).unwrap();
42 assert_eq!(root, dir.path());
43 }
44
45 #[test]
46 fn finds_ready_set_toml() {
47 let dir = tempfile::tempdir().unwrap();
48 std::fs::write(
49 dir.path().join(".ready-set.toml"),
50 "[ready-set]\nschema_version = 1\n",
51 )
52 .unwrap();
53 let inner = dir.path().join("a");
54 std::fs::create_dir_all(&inner).unwrap();
55 let root = detect_project_root(&inner).unwrap();
56 assert_eq!(root, dir.path());
57 }
58
59 #[test]
60 fn falls_back_to_nearest_cargo_toml() {
61 let dir = tempfile::tempdir().unwrap();
62 std::fs::write(dir.path().join("Cargo.toml"), "[package]\nname=\"x\"\n").unwrap();
63 let inner = dir.path().join("src");
64 std::fs::create_dir_all(&inner).unwrap();
65 let root = detect_project_root(&inner).unwrap();
66 assert_eq!(root, dir.path());
67 }
68
69 #[test]
70 fn returns_none_when_nothing_found() {
71 let dir = tempfile::tempdir().unwrap();
72 let inner = dir.path().join("a/b");
73 std::fs::create_dir_all(&inner).unwrap();
74 drop(detect_project_root(&inner));
78 }
79}