use crate::workspace::WorkspaceContext;
use std::path::PathBuf;
pub struct WorkspaceView<'a> {
ctx: &'a WorkspaceContext,
}
#[derive(Debug, Clone)]
pub struct CrateInfo {
pub name: String,
pub crate_root: PathBuf,
pub manifest_path: PathBuf,
pub is_proc_macro: bool,
pub version: semver::Version,
}
impl<'a> WorkspaceView<'a> {
pub fn new(ctx: &'a WorkspaceContext) -> Self {
Self { ctx }
}
pub fn crate_info(&self, crate_name: &str) -> Option<CrateInfo> {
let package = self.ctx.cargo.get_package(crate_name)?;
let manifest_path = package.manifest_path.clone().into_std_path_buf();
let crate_root = manifest_path.parent()?.to_path_buf();
Some(CrateInfo {
name: crate_name.to_string(),
crate_root,
manifest_path,
is_proc_macro: self.ctx.cargo.is_proc_macro(crate_name),
version: package.version.clone(),
})
}
pub fn all_crates(&self) -> Vec<CrateInfo> {
self
.ctx
.graph
.workspace_members()
.iter()
.filter_map(|name| self.crate_info(name))
.collect()
}
pub fn dependents(&self, crate_name: &str) -> crate::error::RailResult<Vec<String>> {
self.ctx.graph.transitive_dependents(crate_name)
}
pub fn file_to_crate(&self, path: &std::path::Path) -> Option<String> {
self.ctx.graph.file_to_crate(path)
}
pub fn is_proc_macro(&self, crate_name: &str) -> bool {
self.ctx.cargo.is_proc_macro(crate_name)
}
pub fn proc_macro_crates(&self) -> &std::collections::HashSet<String> {
self.ctx.cargo.proc_macro_crates()
}
pub fn publish_order(&self) -> crate::error::RailResult<Vec<String>> {
self.ctx.graph.publish_order()
}
pub fn context(&self) -> &WorkspaceContext {
self.ctx
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create_test_context() -> WorkspaceContext {
let current_dir = std::env::current_dir().unwrap();
WorkspaceContext::build(¤t_dir).unwrap()
}
#[test]
fn test_workspace_view_crate_info() {
let ctx = create_test_context();
let view = WorkspaceView::new(&ctx);
let info = view.crate_info("cargo-rail");
assert!(info.is_some(), "Should find cargo-rail");
let info = info.unwrap();
assert_eq!(info.name, "cargo-rail");
assert!(info.crate_root.exists(), "Crate root should exist");
assert!(info.manifest_path.exists(), "Manifest should exist");
assert!(!info.is_proc_macro, "cargo-rail is not a proc-macro");
}
#[test]
fn test_workspace_view_all_crates() {
let ctx = create_test_context();
let view = WorkspaceView::new(&ctx);
let all = view.all_crates();
assert!(!all.is_empty(), "Should have at least one crate");
assert!(all.iter().any(|c| c.name == "cargo-rail"), "Should include cargo-rail");
}
#[test]
fn test_workspace_view_proc_macro() {
let ctx = create_test_context();
let view = WorkspaceView::new(&ctx);
assert!(!view.is_proc_macro("cargo-rail"));
let _proc_macros = view.proc_macro_crates();
}
}