Rust · 8932 bytes Raw Blame History
1 //! wanda wemod - Manage WeMod installation
2
3 use clap::Subcommand;
4 use console::style;
5 use indicatif::{ProgressBar, ProgressStyle};
6 use std::path::PathBuf;
7 use wanda_core::{
8 config::WandaConfig,
9 prefix::PrefixManager,
10 steam::{ProtonManager, SteamInstallation},
11 wemod::{WemodDownloader, WemodInstaller},
12 Result, WandaError,
13 };
14
15 #[derive(Subcommand)]
16 pub enum WemodCommands {
17 /// Show WeMod installation status
18 Status,
19
20 /// Update WeMod to the latest version
21 Update,
22
23 /// Install WeMod into a prefix
24 Install,
25
26 /// Uninstall WeMod from a prefix
27 Uninstall,
28
29 /// Run WeMod standalone (for testing)
30 Run,
31 }
32
33 pub async fn run(cmd: WemodCommands, config_path: Option<PathBuf>) -> Result<()> {
34 let config = match &config_path {
35 Some(path) => WandaConfig::load_from(path)?,
36 None => WandaConfig::load()?,
37 };
38
39 match cmd {
40 WemodCommands::Status => status(&config).await,
41 WemodCommands::Update => update(&config).await,
42 WemodCommands::Install => install(&config).await,
43 WemodCommands::Uninstall => uninstall(&config).await,
44 WemodCommands::Run => run_wemod(&config).await,
45 }
46 }
47
48 async fn status(config: &WandaConfig) -> Result<()> {
49 let mut prefix_manager = PrefixManager::new(config);
50 prefix_manager.load()?;
51
52 let prefix = prefix_manager.get("default");
53
54 println!("WeMod Status:\n");
55
56 match prefix {
57 Some(p) if p.wemod_installed => {
58 println!(
59 " Status: {} Installed",
60 style("OK").green().bold()
61 );
62 if let Some(ref version) = p.wemod_version {
63 println!(" Version: {}", version);
64 }
65 println!(" Path: {}", p.wemod_path().display());
66
67 // Check for updates
68 println!("\nChecking for updates...");
69 let downloader = WemodDownloader::new(config);
70 match downloader.get_latest().await {
71 Ok(release) => {
72 if let Some(ref latest) = release.version {
73 let current = p.wemod_version.as_deref().unwrap_or("unknown");
74 if current != latest {
75 println!(
76 " {} Update available: {} -> {}",
77 style("UPDATE").yellow(),
78 current,
79 latest
80 );
81 println!("\n Run 'wanda wemod update' to update.");
82 } else {
83 println!(" {} Up to date", style("OK").green());
84 }
85 }
86 }
87 Err(e) => {
88 println!(" Could not check for updates: {}", e);
89 }
90 }
91 }
92 Some(_) => {
93 println!(
94 " Status: {} Not installed",
95 style("WARNING").yellow().bold()
96 );
97 println!("\n Run 'wanda wemod install' to install WeMod.");
98 }
99 None => {
100 println!(
101 " Status: {} WANDA not initialized",
102 style("ERROR").red().bold()
103 );
104 println!("\n Run 'wanda init' first.");
105 }
106 }
107
108 Ok(())
109 }
110
111 async fn update(config: &WandaConfig) -> Result<()> {
112 let mut prefix_manager = PrefixManager::new(config);
113 prefix_manager.load()?;
114
115 let prefix = prefix_manager.get("default").ok_or_else(|| WandaError::LaunchFailed {
116 reason: "WANDA not initialized. Run 'wanda init' first.".to_string(),
117 })?;
118
119 println!("Checking for WeMod updates...\n");
120
121 let downloader = WemodDownloader::new(config);
122 let release = downloader.get_latest().await?;
123
124 let current = prefix.wemod_version.as_deref().unwrap_or("unknown");
125 let latest = release.version.as_deref().unwrap_or("unknown");
126
127 if current == latest {
128 println!("WeMod is already up to date (version {}).", current);
129 return Ok(());
130 }
131
132 println!("Current version: {}", current);
133 println!("Latest version: {}", latest);
134 println!("\nDownloading update...");
135
136 let pb = ProgressBar::new(release.size.unwrap_or(0));
137 pb.set_style(
138 ProgressStyle::default_bar()
139 .template("{spinner:.green} [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})")
140 .unwrap()
141 .progress_chars("#>-"),
142 );
143
144 let installer_path = downloader
145 .download(&release, |downloaded, total| {
146 pb.set_length(total);
147 pb.set_position(downloaded);
148 })
149 .await?;
150
151 pb.finish_with_message("Download complete");
152
153 println!("\nInstalling update...");
154
155 let steam = SteamInstallation::discover(config)?;
156 let proton_manager = ProtonManager::discover(&steam, config)?;
157 let proton = proton_manager.get_preferred(config)?;
158
159 let installer = WemodInstaller::new(prefix, proton);
160 installer.install(&installer_path).await?;
161
162 // Update metadata
163 let version = release.version.clone();
164 prefix_manager.update_metadata("default", |p| {
165 p.wemod_version = version;
166 })?;
167
168 println!(
169 "\n{} WeMod updated to version {}!",
170 style("SUCCESS").green().bold(),
171 latest
172 );
173
174 Ok(())
175 }
176
177 async fn install(config: &WandaConfig) -> Result<()> {
178 let mut prefix_manager = PrefixManager::new(config);
179 prefix_manager.load()?;
180
181 let prefix = prefix_manager.get("default").ok_or_else(|| WandaError::LaunchFailed {
182 reason: "WANDA not initialized. Run 'wanda init' first.".to_string(),
183 })?;
184
185 if prefix.wemod_installed {
186 println!("WeMod is already installed.");
187 println!("Use 'wanda wemod update' to update to the latest version.");
188 return Ok(());
189 }
190
191 println!("Installing WeMod...\n");
192
193 let downloader = WemodDownloader::new(config);
194 let release = downloader.get_latest().await?;
195
196 if let Some(ref version) = release.version {
197 println!("Version: {}", version);
198 }
199
200 let pb = ProgressBar::new(release.size.unwrap_or(0));
201 pb.set_style(
202 ProgressStyle::default_bar()
203 .template("{spinner:.green} [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})")
204 .unwrap()
205 .progress_chars("#>-"),
206 );
207
208 let installer_path = downloader
209 .download(&release, |downloaded, total| {
210 pb.set_length(total);
211 pb.set_position(downloaded);
212 })
213 .await?;
214
215 pb.finish_with_message("Download complete");
216
217 println!("\nInstalling...");
218
219 let steam = SteamInstallation::discover(config)?;
220 let proton_manager = ProtonManager::discover(&steam, config)?;
221 let proton = proton_manager.get_preferred(config)?;
222
223 let installer = WemodInstaller::new(prefix, proton);
224 installer.install(&installer_path).await?;
225
226 let version = release.version.clone();
227 prefix_manager.update_metadata("default", |p| {
228 p.wemod_installed = true;
229 p.wemod_version = version;
230 })?;
231
232 println!(
233 "\n{} WeMod installed successfully!",
234 style("SUCCESS").green().bold()
235 );
236
237 Ok(())
238 }
239
240 async fn uninstall(config: &WandaConfig) -> Result<()> {
241 let mut prefix_manager = PrefixManager::new(config);
242 prefix_manager.load()?;
243
244 let prefix = prefix_manager.get("default").ok_or_else(|| WandaError::LaunchFailed {
245 reason: "WANDA not initialized.".to_string(),
246 })?;
247
248 if !prefix.wemod_installed {
249 println!("WeMod is not installed.");
250 return Ok(());
251 }
252
253 let steam = SteamInstallation::discover(config)?;
254 let proton_manager = ProtonManager::discover(&steam, config)?;
255 let proton = proton_manager.get_preferred(config)?;
256
257 println!("Uninstalling WeMod...");
258
259 let installer = WemodInstaller::new(prefix, proton);
260 installer.uninstall().await?;
261
262 prefix_manager.update_metadata("default", |p| {
263 p.wemod_installed = false;
264 p.wemod_version = None;
265 })?;
266
267 println!("WeMod uninstalled.");
268
269 Ok(())
270 }
271
272 async fn run_wemod(config: &WandaConfig) -> Result<()> {
273 let mut prefix_manager = PrefixManager::new(config);
274 prefix_manager.load()?;
275
276 let prefix = prefix_manager.get("default").ok_or(WandaError::WemodNotInstalled)?;
277
278 if !prefix.wemod_installed {
279 return Err(WandaError::WemodNotInstalled);
280 }
281
282 let steam = SteamInstallation::discover(config)?;
283 let proton_manager = ProtonManager::discover(&steam, config)?;
284 let proton = proton_manager.get_preferred(config)?;
285
286 println!("Starting WeMod...");
287
288 let installer = WemodInstaller::new(prefix, proton);
289 let mut child = installer.run().await?;
290
291 println!("WeMod is running. Press Ctrl+C to stop.");
292
293 // Wait for WeMod to exit
294 let _ = child.wait().await;
295
296 println!("WeMod closed.");
297
298 Ok(())
299 }
300