vx_cli/commands/
update.rs1use crate::ui::UI;
4use vx_core::{PluginRegistry, Result, VxError};
5
6pub async fn handle(registry: &PluginRegistry, tool_name: Option<&str>, apply: bool) -> Result<()> {
7 match tool_name {
8 Some(tool_name) => {
9 update_single_tool(registry, tool_name, apply).await
11 }
12 None => {
13 update_all_tools(registry, apply).await
15 }
16 }
17}
18
19async fn update_single_tool(registry: &PluginRegistry, tool_name: &str, apply: bool) -> Result<()> {
20 let tool = registry
21 .get_tool(tool_name)
22 .ok_or_else(|| VxError::ToolNotFound {
23 tool_name: tool_name.to_string(),
24 })?;
25
26 let installed_versions = tool.get_installed_versions().await?;
28 if installed_versions.is_empty() {
29 UI::warn(&format!("{} is not installed", tool_name));
30 UI::hint(&format!("Use 'vx install {}' to install it", tool_name));
31 return Ok(());
32 }
33
34 UI::info(&format!("Checking for updates to {}...", tool_name));
36 let versions = tool.fetch_versions(false).await?;
37 if versions.is_empty() {
38 UI::warn(&format!("No versions found for {}", tool_name));
39 return Ok(());
40 }
41
42 let latest_version = &versions[0].version;
43 let current_version = &installed_versions[0]; if current_version == latest_version {
46 UI::success(&format!(
47 "{} {} is already up to date",
48 tool_name, current_version
49 ));
50 return Ok(());
51 }
52
53 UI::info(&format!(
54 "Update available: {} {} → {}",
55 tool_name, current_version, latest_version
56 ));
57
58 if !apply {
59 UI::hint("Use --apply to perform the update");
60 return Ok(());
61 }
62
63 UI::info(&format!("Updating {} to {}...", tool_name, latest_version));
65
66 match tool.install_version(latest_version, false).await {
67 Ok(()) => {
68 UI::success(&format!(
69 "Successfully updated {} to {}",
70 tool_name, latest_version
71 ));
72 }
73 Err(e) => {
74 UI::error(&format!("Failed to update {}: {}", tool_name, e));
75 return Err(e);
76 }
77 }
78
79 Ok(())
80}
81
82async fn update_all_tools(registry: &PluginRegistry, apply: bool) -> Result<()> {
83 let tools = registry.get_all_tools();
84
85 if tools.is_empty() {
86 UI::warn("No tools available");
87 return Ok(());
88 }
89
90 UI::info("Checking for updates to all tools...");
91
92 let mut updates_available = Vec::new();
93 let mut errors = Vec::new();
94
95 for tool in tools {
96 match check_tool_update(&*tool).await {
97 Ok(Some((current, latest))) => {
98 updates_available.push((tool.name().to_string(), current, latest));
99 }
100 Ok(None) => {
101 }
103 Err(e) => {
104 UI::warn(&format!(
105 "Failed to check updates for {}: {}",
106 tool.name(),
107 e
108 ));
109 errors.push((tool.name().to_string(), e));
110 }
111 }
112 }
113
114 if updates_available.is_empty() {
115 UI::success("All tools are up to date");
116 return Ok(());
117 }
118
119 UI::info(&format!(
120 "Found {} updates available:",
121 updates_available.len()
122 ));
123 for (tool_name, current, latest) in &updates_available {
124 UI::item(&format!("{}: {} → {}", tool_name, current, latest));
125 }
126
127 if !apply {
128 UI::hint("Use --apply to perform all updates");
129 return Ok(());
130 }
131
132 UI::info("Updating all tools...");
134
135 for (tool_name, _current, latest) in updates_available {
136 if let Some(tool) = registry.get_tool(&tool_name) {
137 match tool.install_version(&latest, false).await {
138 Ok(()) => {
139 UI::success(&format!("Updated {} to {}", tool_name, latest));
140 }
141 Err(e) => {
142 UI::error(&format!("Failed to update {}: {}", tool_name, e));
143 errors.push((tool_name, e));
144 }
145 }
146 }
147 }
148
149 if errors.is_empty() {
150 UI::success("All tools updated successfully");
151 } else {
152 UI::warn(&format!("Some updates failed ({} errors)", errors.len()));
153 }
154
155 Ok(())
156}
157
158async fn check_tool_update(tool: &dyn vx_core::VxTool) -> Result<Option<(String, String)>> {
159 let installed_versions = tool.get_installed_versions().await?;
161 if installed_versions.is_empty() {
162 return Ok(None); }
164
165 let versions = tool.fetch_versions(false).await?;
167 if versions.is_empty() {
168 return Ok(None); }
170
171 let current_version = &installed_versions[0];
172 let latest_version = &versions[0].version;
173
174 if current_version != latest_version {
175 Ok(Some((current_version.clone(), latest_version.clone())))
176 } else {
177 Ok(None) }
179}