1use std::fs;
2use std::path::{Path, PathBuf};
3
4use anyhow::Result;
5use xshell::Shell;
6
7pub fn find_files<P: AsRef<Path>>(dir: P, extension: &str) -> Result<Vec<PathBuf>> {
8 let mut result = Vec::new();
9 let dir_path = dir.as_ref();
10 find_files_recursive(dir_path, extension, &mut result)?;
11 Ok(result)
12}
13
14fn find_files_recursive(dir: &Path, extension: &str, result: &mut Vec<PathBuf>) -> Result<()> {
15 for entry_result in fs::read_dir(dir)? {
16 let entry = entry_result?;
17 let path = entry.path();
18
19 if path.is_dir() {
20 find_files_recursive(&path, extension, result)?;
21 } else if path.is_file() && path.extension().is_some_and(|ext| ext == extension) {
22 result.push(path);
23 }
24 }
25 Ok(())
26}
27
28pub fn project_root() -> PathBuf {
29 Path::new(env!("CARGO_MANIFEST_DIR"))
30 .parent()
31 .expect("Failed to find project root")
32 .to_path_buf()
33}
34
35pub fn to_relative_paths<P: AsRef<Path>>(paths: Vec<PathBuf>, base_dir: P) -> Vec<PathBuf> {
36 let base_path = base_dir.as_ref();
37 paths
38 .into_iter()
39 .filter_map(|path| path.strip_prefix(base_path).ok().map(PathBuf::from))
40 .collect()
41}
42
43pub fn verbose_cd<P: AsRef<Path>>(sh: &Shell, dir: P) {
44 sh.change_dir(dir);
45 eprintln!(
46 "\n$ cd {}{}",
47 sh.current_dir().display(),
48 std::path::MAIN_SEPARATOR
49 );
50}