1use std::path::{Path, PathBuf};
4use std::process::Command;
5
6pub fn find_manifest_dir(start: &Path) -> Option<PathBuf> {
8 let mut dir = if start.is_dir() {
9 Some(start.to_path_buf())
10 } else {
11 start.parent().map(|p| p.to_path_buf())
12 };
13 while let Some(d) = dir {
14 if d.join("Cargo.toml").is_file() {
15 return Some(d);
16 }
17 dir = d.parent().map(|p| p.to_path_buf());
18 }
19 None
20}
21
22pub struct CheckResult {
24 pub ok: bool,
25 pub stderr: String,
26}
27
28pub fn cargo_check(manifest_dir: &Path, all_targets: bool) -> CheckResult {
30 let mut cmd = Command::new("cargo");
31 cmd.arg("check").arg("--quiet").current_dir(manifest_dir);
32 if all_targets {
33 cmd.arg("--all-targets");
34 }
35 cmd.env("RUSTFLAGS", "--cap-lints=warn");
38 match cmd.output() {
39 Ok(out) => CheckResult {
40 ok: out.status.success(),
41 stderr: String::from_utf8_lossy(&out.stderr).to_string(),
42 },
43 Err(e) => CheckResult {
44 ok: false,
45 stderr: format!("failed to run cargo check: {e}"),
46 },
47 }
48}
49
50pub fn error_excerpt(stderr: &str) -> String {
52 let lines: Vec<&str> = stderr
53 .lines()
54 .filter(|l| {
55 let t = l.trim_start();
56 t.starts_with("error") || t.starts_with("-->") || t.contains("not found") || t.contains("cannot find")
57 })
58 .take(12)
59 .collect();
60 if lines.is_empty() {
61 stderr.lines().rev().take(8).collect::<Vec<_>>().into_iter().rev().collect::<Vec<_>>().join("\n")
62 } else {
63 lines.join("\n")
64 }
65}