ready_set_rust/
members.rs1use std::collections::BTreeSet;
4use std::path::Path;
5
6use walkdir::WalkDir;
7
8const MAX_DEPTH: usize = 6;
9
10#[must_use]
15pub fn discover(root: &Path) -> Vec<String> {
16 let mut out: BTreeSet<String> = BTreeSet::new();
17 let mut walker = WalkDir::new(root).max_depth(MAX_DEPTH).into_iter();
18
19 while let Some(entry) = walker.next() {
20 let Ok(entry) = entry else { continue };
21 if !entry.file_type().is_dir() {
22 continue;
23 }
24 if is_skipped(entry.path(), root) {
25 walker.skip_current_dir();
26 continue;
27 }
28
29 let manifest = entry.path().join("Cargo.toml");
30 if !manifest.is_file() || entry.path() == root {
31 continue;
32 }
33 if let Ok(raw) = std::fs::read_to_string(&manifest)
34 && raw.contains("[workspace]")
35 {
36 walker.skip_current_dir();
37 continue;
38 }
39
40 if let Ok(rel) = entry.path().strip_prefix(root) {
41 let s = rel.to_string_lossy().replace('\\', "/");
42 if !s.is_empty() {
43 out.insert(s);
44 }
45 }
46 }
47
48 out.into_iter().collect()
49}
50
51fn is_skipped(path: &Path, root: &Path) -> bool {
52 if path == root {
53 return false;
54 }
55 let Some(name) = path.file_name().and_then(|s| s.to_str()) else {
56 return false;
57 };
58 if name == "target" || name == "node_modules" || name == ".git" {
59 return true;
60 }
61 name.starts_with('.') && name != "." && name != ".."
62}