Skip to main content

null_e/plugins/
rust.rs

1//! Rust/Cargo plugin
2
3use crate::core::{Artifact, ArtifactKind, ArtifactMetadata, MarkerKind, ProjectKind, ProjectMarker};
4use crate::error::Result;
5use crate::plugins::Plugin;
6use std::path::Path;
7
8/// Plugin for Rust/Cargo projects
9pub struct RustPlugin;
10
11impl Plugin for RustPlugin {
12    fn id(&self) -> &'static str {
13        "rust"
14    }
15
16    fn name(&self) -> &'static str {
17        "Rust (Cargo)"
18    }
19
20    fn supported_kinds(&self) -> &[ProjectKind] {
21        &[ProjectKind::Rust]
22    }
23
24    fn markers(&self) -> Vec<ProjectMarker> {
25        vec![
26            ProjectMarker {
27                indicator: MarkerKind::File("Cargo.toml"),
28                kind: ProjectKind::Rust,
29                priority: 60,
30            },
31        ]
32    }
33
34    fn detect(&self, path: &Path) -> Option<ProjectKind> {
35        if path.join("Cargo.toml").is_file() {
36            Some(ProjectKind::Rust)
37        } else {
38            None
39        }
40    }
41
42    fn find_artifacts(&self, project_root: &Path) -> Result<Vec<Artifact>> {
43        let mut artifacts = Vec::new();
44
45        // target directory - the BIG one for Rust
46        let target = project_root.join("target");
47        if target.exists() {
48            artifacts.push(Artifact {
49                path: target,
50                kind: ArtifactKind::BuildOutput,
51                size: 0,
52                file_count: 0,
53                age: None,
54                metadata: ArtifactMetadata {
55                    restorable: true,
56                    restore_command: Some("cargo build".into()),
57                    lockfile: Some(project_root.join("Cargo.lock")),
58                    restore_time_estimate: Some(60), // Rust builds can be slow
59                    ..Default::default()
60                },
61            });
62        }
63
64        // debug artifacts in target/debug (if we want to be more granular)
65        // For now, we just clean the whole target directory
66
67        Ok(artifacts)
68    }
69
70    fn cleanable_dirs(&self) -> &[&'static str] {
71        &["target"]
72    }
73
74    fn priority(&self) -> u8 {
75        60
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82    use tempfile::TempDir;
83
84    #[test]
85    fn test_detect_rust() {
86        let temp = TempDir::new().unwrap();
87        std::fs::write(
88            temp.path().join("Cargo.toml"),
89            r#"[package]
90name = "test"
91version = "0.1.0"
92"#,
93        )
94        .unwrap();
95
96        let plugin = RustPlugin;
97        assert_eq!(plugin.detect(temp.path()), Some(ProjectKind::Rust));
98    }
99
100    #[test]
101    fn test_no_detect_without_cargo() {
102        let temp = TempDir::new().unwrap();
103
104        let plugin = RustPlugin;
105        assert_eq!(plugin.detect(temp.path()), None);
106    }
107
108    #[test]
109    fn test_find_artifacts() {
110        let temp = TempDir::new().unwrap();
111        std::fs::write(temp.path().join("Cargo.toml"), "[package]").unwrap();
112        std::fs::create_dir(temp.path().join("target")).unwrap();
113
114        let plugin = RustPlugin;
115        let artifacts = plugin.find_artifacts(temp.path()).unwrap();
116
117        assert_eq!(artifacts.len(), 1);
118        assert_eq!(artifacts[0].name(), "target");
119        assert_eq!(artifacts[0].kind, ArtifactKind::BuildOutput);
120    }
121}