From 5a5a07c7fad31641d032a743e4e87ffb58ade17d Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Fri, 22 May 2026 22:10:19 +0800 Subject: Initial commit --- rola-vcs/src/tools/dir_search.rs | 54 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 rola-vcs/src/tools/dir_search.rs (limited to 'rola-vcs/src/tools') 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, pattern: DirSearchPattern) -> Option { + 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 +} -- cgit