Skip to main content

null_e/plugins/
go.rs

1//! Go 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 Go projects
9pub struct GoPlugin;
10
11impl Plugin for GoPlugin {
12    fn id(&self) -> &'static str {
13        "go"
14    }
15
16    fn name(&self) -> &'static str {
17        "Go"
18    }
19
20    fn supported_kinds(&self) -> &[ProjectKind] {
21        &[ProjectKind::Go]
22    }
23
24    fn markers(&self) -> Vec<ProjectMarker> {
25        vec![
26            ProjectMarker {
27                indicator: MarkerKind::File("go.mod"),
28                kind: ProjectKind::Go,
29                priority: 60,
30            },
31            ProjectMarker {
32                indicator: MarkerKind::File("go.sum"),
33                kind: ProjectKind::Go,
34                priority: 55,
35            },
36        ]
37    }
38
39    fn detect(&self, path: &Path) -> Option<ProjectKind> {
40        if path.join("go.mod").is_file() {
41            Some(ProjectKind::Go)
42        } else {
43            None
44        }
45    }
46
47    fn find_artifacts(&self, project_root: &Path) -> Result<Vec<Artifact>> {
48        let mut artifacts = Vec::new();
49
50        // vendor directory (vendored dependencies)
51        let vendor = project_root.join("vendor");
52        if vendor.exists() {
53            artifacts.push(Artifact {
54                path: vendor,
55                kind: ArtifactKind::Dependencies,
56                size: 0,
57                file_count: 0,
58                age: None,
59                metadata: ArtifactMetadata {
60                    restorable: true,
61                    restore_command: Some("go mod vendor".into()),
62                    lockfile: Some(project_root.join("go.sum")),
63                    ..Default::default()
64                },
65            });
66        }
67
68        // bin directory (local binaries)
69        let bin = project_root.join("bin");
70        if bin.exists() {
71            artifacts.push(Artifact {
72                path: bin,
73                kind: ArtifactKind::BuildOutput,
74                size: 0,
75                file_count: 0,
76                age: None,
77                metadata: ArtifactMetadata::restorable("go build"),
78            });
79        }
80
81        // dist directory (release builds)
82        let dist = project_root.join("dist");
83        if dist.exists() {
84            artifacts.push(Artifact {
85                path: dist,
86                kind: ArtifactKind::BuildOutput,
87                size: 0,
88                file_count: 0,
89                age: None,
90                metadata: ArtifactMetadata::restorable("go build"),
91            });
92        }
93
94        Ok(artifacts)
95    }
96
97    fn cleanable_dirs(&self) -> &[&'static str] {
98        &["vendor"]
99    }
100
101    fn priority(&self) -> u8 {
102        55
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109    use tempfile::TempDir;
110
111    #[test]
112    fn test_detect_go() {
113        let temp = TempDir::new().unwrap();
114        std::fs::write(
115            temp.path().join("go.mod"),
116            "module example.com/test\n\ngo 1.21\n",
117        )
118        .unwrap();
119
120        let plugin = GoPlugin;
121        assert_eq!(plugin.detect(temp.path()), Some(ProjectKind::Go));
122    }
123
124    #[test]
125    fn test_find_artifacts() {
126        let temp = TempDir::new().unwrap();
127        std::fs::write(temp.path().join("go.mod"), "module test").unwrap();
128        std::fs::create_dir(temp.path().join("vendor")).unwrap();
129
130        let plugin = GoPlugin;
131        let artifacts = plugin.find_artifacts(temp.path()).unwrap();
132
133        assert_eq!(artifacts.len(), 1);
134        assert_eq!(artifacts[0].name(), "vendor");
135    }
136}