vx_tool_rust/
rust_tool.rs1use std::collections::HashMap;
4use vx_core::{
5 GitHubVersionParser, HttpUtils, Result, RustUrlBuilder, ToolContext, ToolExecutionResult,
6 VersionInfo, VxTool,
7};
8
9macro_rules! rust_vx_tool {
11 ($name:ident, $cmd:literal, $desc:literal) => {
12 #[derive(Debug, Clone)]
13 pub struct $name {
14 _url_builder: RustUrlBuilder,
15 _version_parser: GitHubVersionParser,
16 }
17
18 impl $name {
19 pub fn new() -> Self {
20 Self {
21 _url_builder: RustUrlBuilder::new(),
22 _version_parser: GitHubVersionParser::new("rust-lang", "rust"),
23 }
24 }
25 }
26
27 #[async_trait::async_trait]
28 impl VxTool for $name {
29 fn name(&self) -> &str {
30 $cmd
31 }
32
33 fn description(&self) -> &str {
34 $desc
35 }
36
37 fn aliases(&self) -> Vec<&str> {
38 vec![]
39 }
40
41 async fn fetch_versions(&self, include_prerelease: bool) -> Result<Vec<VersionInfo>> {
42 let json = HttpUtils::fetch_json(RustUrlBuilder::versions_url()).await?;
44 GitHubVersionParser::parse_versions(&json, include_prerelease)
45 }
46
47 async fn install_version(&self, version: &str, force: bool) -> Result<()> {
48 if !force && self.is_version_installed(version).await? {
49 return Err(vx_core::VxError::VersionAlreadyInstalled {
50 tool_name: self.name().to_string(),
51 version: version.to_string(),
52 });
53 }
54
55 let install_dir = self.get_version_install_dir(version);
56 let _exe_path = self.default_install_workflow(version, &install_dir).await?;
57
58 if !self.is_version_installed(version).await? {
60 return Err(vx_core::VxError::InstallationFailed {
61 tool_name: self.name().to_string(),
62 version: version.to_string(),
63 message: "Installation verification failed".to_string(),
64 });
65 }
66
67 Ok(())
68 }
69
70 async fn execute(
71 &self,
72 args: &[String],
73 context: &ToolContext,
74 ) -> Result<ToolExecutionResult> {
75 self.default_execute_workflow(args, context).await
76 }
77
78 async fn get_download_url(&self, version: &str) -> Result<Option<String>> {
79 let rust_url_builder = RustUrlBuilder::new();
80 Ok(rust_url_builder.download_url(version))
81 }
82
83 fn metadata(&self) -> HashMap<String, String> {
84 let mut meta = HashMap::new();
85 meta.insert(
86 "homepage".to_string(),
87 "https://www.rust-lang.org/".to_string(),
88 );
89 meta.insert("ecosystem".to_string(), "rust".to_string());
90 meta.insert(
91 "repository".to_string(),
92 "https://github.com/rust-lang/rust".to_string(),
93 );
94 meta.insert("license".to_string(), "MIT OR Apache-2.0".to_string());
95 meta
96 }
97 }
98
99 impl Default for $name {
100 fn default() -> Self {
101 Self::new()
102 }
103 }
104 };
105}
106
107rust_vx_tool!(CargoTool, "cargo", "Rust package manager and build tool");
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn test_cargo_tool_creation() {
116 let tool = CargoTool::new();
117 assert_eq!(tool.name(), "cargo");
118 assert!(!tool.description().is_empty());
119 assert!(tool.aliases().is_empty());
120 }
121
122 #[test]
123 fn test_rust_tool_metadata() {
124 let tool = CargoTool::new();
125 let metadata = tool.metadata();
126
127 assert!(metadata.contains_key("homepage"));
128 assert!(metadata.contains_key("ecosystem"));
129 assert_eq!(metadata.get("ecosystem"), Some(&"rust".to_string()));
130 }
131}