1use crate::{Result, VersionInfo};
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use std::path::{Path, PathBuf};
7
8#[async_trait::async_trait]
10pub trait AsyncTool: Send + Sync {
11 fn name(&self) -> &str;
13
14 fn description(&self) -> &str {
16 "A development tool"
17 }
18
19 fn aliases(&self) -> Vec<&str> {
21 vec![]
22 }
23
24 async fn fetch_versions(&self, include_prerelease: bool) -> Result<Vec<VersionInfo>>;
26
27 async fn install_version(&self, version: &str) -> Result<PathBuf>;
29
30 async fn get_installed_versions(&self) -> Result<Vec<String>>;
32
33 async fn uninstall_version(&self, version: &str) -> Result<()>;
35
36 async fn get_download_url(&self, version: &str) -> Result<Option<String>>;
38
39 fn get_executable_path(&self, version: &str) -> PathBuf;
41
42 async fn execute(&self, context: &ToolContext) -> Result<i32>;
44
45 async fn is_version_installed(&self, version: &str) -> Result<bool> {
47 let installed_versions = self.get_installed_versions().await?;
48 Ok(installed_versions.contains(&version.to_string()))
49 }
50
51 fn get_base_install_dir(&self) -> PathBuf {
53 dirs::home_dir()
54 .unwrap_or_else(|| PathBuf::from("."))
55 .join(".vx")
56 .join("tools")
57 .join(self.name())
58 }
59
60 fn get_version_install_dir(&self, version: &str) -> PathBuf {
62 self.get_base_install_dir().join(version)
63 }
64}
65
66pub trait Environment: Send + Sync {
68 fn name(&self) -> &str;
70
71 fn get_tool_version(&self, tool_name: &str) -> Option<String>;
73
74 fn set_tool_version(&mut self, tool_name: &str, version: String) -> Result<()>;
76
77 fn get_environment_path(&self) -> PathBuf;
79
80 fn activate(&self) -> Result<ToolContext>;
82
83 fn list_tools(&self) -> Result<HashMap<String, String>>;
85}
86
87pub trait Configuration: Send + Sync {
89 fn get_global_tool_version(&self, tool_name: &str) -> Option<String>;
91
92 fn set_global_tool_version(&self, tool_name: &str, version: String) -> Result<()>;
94
95 fn get_project_tool_version(&self, tool_name: &str, project_path: &Path) -> Option<String>;
97
98 fn set_project_tool_version(
100 &self,
101 tool_name: &str,
102 version: String,
103 project_path: &Path,
104 ) -> Result<()>;
105
106 fn get_active_environment(&self) -> Option<String>;
108
109 fn set_active_environment(&self, env_name: Option<String>) -> Result<()>;
111
112 fn resolve_tool_version(
114 &self,
115 tool_name: &str,
116 cli_version: Option<&str>,
117 project_path: Option<&Path>,
118 ) -> Option<String>;
119}
120
121pub trait Plugin: Send + Sync {
123 fn name(&self) -> &str;
125
126 fn description(&self) -> &str {
128 "A vx plugin"
129 }
130
131 fn version(&self) -> &str {
133 "0.1.0"
134 }
135
136 fn tools(&self) -> Vec<Box<dyn AsyncTool>>;
138
139 fn supports_tool(&self, tool_name: &str) -> bool;
141}
142
143#[derive(Debug, Clone)]
145pub struct ToolContext {
146 pub tool_name: String,
147 pub version: String,
148 pub args: Vec<String>,
149 pub working_directory: Option<PathBuf>,
150 pub environment_variables: HashMap<String, String>,
151 pub environment: Option<String>, pub use_system_path: bool, }
154
155impl ToolContext {
156 pub fn new(tool_name: String, version: String, args: Vec<String>) -> Self {
157 Self {
158 tool_name,
159 version,
160 args,
161 working_directory: None,
162 environment_variables: HashMap::new(),
163 environment: None,
164 use_system_path: false,
165 }
166 }
167}
168
169#[derive(Debug)]
171pub struct ToolExecutionResult {
172 pub exit_code: i32,
173 pub stdout: Option<String>,
174 pub stderr: Option<String>,
175}
176
177#[derive(Debug, Clone, Serialize, Deserialize)]
179pub struct ToolInfo {
180 pub name: String,
181 pub description: String,
182 pub aliases: Vec<String>,
183 pub installed_versions: Vec<String>,
184 pub current_version: Option<String>,
185 pub latest_version: Option<String>,
186}
187
188#[derive(Debug, Clone, Serialize, Deserialize)]
190pub struct ToolStatus {
191 pub installed: bool,
192 pub current_version: Option<String>,
193 pub installed_versions: Vec<String>,
194}
195
196pub trait Tool: Send + Sync {
199 fn name(&self) -> &str;
201
202 fn description(&self) -> &str {
204 "A development tool"
205 }
206
207 fn homepage(&self) -> Option<&str> {
209 None
210 }
211
212 fn is_installed(&self) -> Result<bool>;
214
215 fn get_version(&self) -> Result<Option<String>>;
217
218 fn get_executable_path(&self, version: &str, install_dir: &Path) -> PathBuf;
220
221 fn execute(&self, args: &[String]) -> Result<i32>;
223
224 fn supports_auto_install(&self) -> bool {
226 true
227 }
228
229 fn get_info(&self) -> ToolInfo {
231 ToolInfo {
232 name: self.name().to_string(),
233 description: self.description().to_string(),
234 aliases: vec![],
235 installed_versions: vec![],
236 current_version: self.get_version().unwrap_or_default(),
237 latest_version: None,
238 }
239 }
240}