diff options
Diffstat (limited to 'rola-vcs/src/tools')
| -rw-r--r-- | rola-vcs/src/tools/dir_search.rs | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/rola-vcs/src/tools/dir_search.rs b/rola-vcs/src/tools/dir_search.rs new file mode 100644 index 0000000..3d32c70 --- /dev/null +++ b/rola-vcs/src/tools/dir_search.rs @@ -0,0 +1,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 +} |
