blob: 3d32c700e8c177d5bfb2fd2a454363dcde45843a (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
use std::path::PathBuf;
pub enum DirSearchPattern<'a> {
File(&'a str),
Dir(&'a str),
}
/// Searches upward from the given path towards parent directories.
/// If any ancestor directory contains a file or directory matching the pattern,
/// returns that ancestor directory's path.
pub fn dir_search_prev(path: impl Into<PathBuf>, pattern: DirSearchPattern) -> Option<PathBuf> {
let mut current: PathBuf = path.into();
// Canonicalize the path if possible to ensure absolute traversal
if let Ok(canonical) = current.canonicalize() {
current = canonical;
} else {
// If canonicalization fails (e.g. path does not exist yet),
// try to make it absolute using current dir
if current.is_relative()
&& let Ok(cwd) = std::env::current_dir() {
current = cwd.join(¤t);
}
}
loop {
// Check if the current directory exists and is a directory
if current.is_dir() {
let has_match = match &pattern {
DirSearchPattern::File(name) => {
let mut entry = current.clone();
entry.push(name);
entry.is_file()
}
DirSearchPattern::Dir(name) => {
let mut entry = current.clone();
entry.push(name);
entry.is_dir()
}
};
if has_match {
return Some(current);
}
}
// Try to go to the parent directory
if !current.pop() {
// pop() returns false when there's no parent
break;
}
}
None
}
|