Something went wrong. Try again.
Identities for entities did.bot
agent llm did
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126//! Which crate and which build target a workspace file belongs to.//!//! `cargo metadata` is the only thing that knows this. A path alone does not://! `crates/didbot-name/src/tests.rs` is a unit-test module inside the lib//! target, while `crates/didbot-tls/tests/rotation.rs` is a target of its own,//! and the reference index has to tell those apart to answer `dead-pub`.
use anyhow::{Context, Result};use serde_json::Value;use std::collections::BTreeMap;use std::path::Path;use std::process::Command;
/// A declared dependency between two workspace crates.pub struct Dep { pub from: String, pub to: String, pub kind: String,}
pub struct Layout { /// (manifest directory relative to the workspace root, package name), /// longest directory first so a prefix match lands on the inner package. packages: Vec<(String, String)>, has_lib: BTreeMap<String, bool>, pub deps: Vec<Dep>,}
impl Layout { /// Reads the workspace layout with `cargo metadata --no-deps`. pub fn probe(root: &Path) -> Result<Self> { let out = Command::new("cargo") .args(["metadata", "--no-deps", "--format-version", "1"]) .current_dir(root) .output() .context("running cargo metadata")?; if !out.status.success() { anyhow::bail!( "cargo metadata failed: {}", String::from_utf8_lossy(&out.stderr) ); } let meta: Value = serde_json::from_slice(&out.stdout)?; let root_str = root.to_string_lossy().to_string(); let mut packages = Vec::new(); let mut has_lib = BTreeMap::new(); let mut names = Vec::new(); for pkg in meta["packages"].as_array().unwrap_or(&Vec::new()) { let name = pkg["name"].as_str().unwrap_or_default().to_string(); let manifest = pkg["manifest_path"].as_str().unwrap_or_default(); let dir = Path::new(manifest).parent().unwrap_or(Path::new("")); let rel = dir .to_string_lossy() .strip_prefix(&root_str) .unwrap_or_default() .trim_start_matches('/') .to_string(); let lib = pkg["targets"] .as_array() .map(|ts| { ts.iter().any(|t| { t["kind"] .as_array() .is_some_and(|ks| ks.iter().any(|k| k == "lib" || k == "proc-macro")) }) }) .unwrap_or(false); has_lib.insert(name.clone(), lib); names.push(name.clone()); packages.push((rel, name)); } packages.sort_by_key(|(dir, _)| std::cmp::Reverse(dir.len()));
let mut deps = Vec::new(); for pkg in meta["packages"].as_array().unwrap_or(&Vec::new()) { let from = pkg["name"].as_str().unwrap_or_default().to_string(); for dep in pkg["dependencies"].as_array().unwrap_or(&Vec::new()) { let to = dep["name"].as_str().unwrap_or_default().to_string(); if !names.contains(&to) { continue; } deps.push(Dep { from: from.clone(), to, kind: dep["kind"].as_str().unwrap_or("normal").to_string(), }); } } Ok(Layout { packages, has_lib, deps, }) }
/// The crate a workspace-relative file belongs to, and the kind of build /// target it is compiled into. pub fn locate(&self, file: &str) -> Option<(&str, &'static str)> { let (dir, name) = self .packages .iter() .find(|(dir, _)| dir.is_empty() || file.starts_with(&format!("{dir}/")))?; let rel = if dir.is_empty() { file } else { &file[dir.len() + 1..] }; let kind = if rel.starts_with("tests/") { "test" } else if rel.starts_with("benches/") { "bench" } else if rel.starts_with("examples/") { "example" } else if rel == "build.rs" { "build" } else if rel.starts_with("src/bin/") || rel == "src/main.rs" { "bin" } else if self.has_lib.get(name).copied().unwrap_or(false) { "lib" } else { "bin" }; Some((name.as_str(), kind)) }}