diff --git a/src/commands/app/cleanup.rs b/src/commands/app/cleanup.rs index cf091797..e3ccde74 100644 --- a/src/commands/app/cleanup.rs +++ b/src/commands/app/cleanup.rs @@ -1,15 +1,39 @@ use clap::Parser; -use sprinkles::{config, contexts::ScoopContext}; +use sprinkles::{contexts::ScoopContext, packages::reference::package}; + +use crate::{ + commands::outdated::apps, handlers::handle_installed_apps, output::colours::eprintln_yellow, +}; #[derive(Debug, Clone, Parser)] /// Cleanup apps by removing old versions pub struct Args { + #[clap(help = "The app(s) to cleanup")] + apps: Vec, + + #[clap(short, long, help = "Cleanup all installed apps")] + all: bool, + #[clap(from_global)] - json: bool, + assume_yes: bool, + + #[clap( + long, + help = "Print what would be done, but don't actually do anything" + )] + dry_run: bool, } impl super::Command for Args { async fn runner(self, ctx: &impl ScoopContext) -> anyhow::Result<()> { + let cleanup_apps = match handle_installed_apps(ctx, self.all, self.apps)?.as_deref() { + Some([]) | None => { + eprintln_yellow!("No apps selected. Exiting now."); + return Ok(()); + } + Some(apps) => apps, + }; + unimplemented!() } } diff --git a/src/handlers.rs b/src/handlers.rs new file mode 100644 index 00000000..421415a2 --- /dev/null +++ b/src/handlers.rs @@ -0,0 +1,78 @@ +use std::io; + +use sprinkles::{ + contexts::ScoopContext, + packages::reference::{manifest, package}, +}; + +use crate::output::colours::{bright_red, green, yellow}; + +/// This will get all apps if all is true and no apps were passed. +/// +/// If all is false and apps are passed, it will only return those apps. +/// +/// If all is true and apps are passed, it will prompt the user to select which collection to choose. +/// +/// If the return value is empty, that means no apps were provided and all was false. +pub fn handle_installed_apps( + ctx: &impl ScoopContext, + all: bool, + apps: Vec, +) -> io::Result>> { + if all { + let installed_apps: Vec = { + let installed_apps = ctx.installed_apps()?; + let manifest_paths = installed_apps.into_iter().filter_map(|path| { + let manifest_path = path.join("current").join("manifest.json"); + + manifest_path + .try_exists() + .ok() + .and_then(|exists| exists.then_some(manifest_path)) + }); + + let references = manifest_paths + .map(manifest::Reference::File) + .map(manifest::Reference::into_package_ref); + + references.collect() + }; + + if apps.is_empty() { + Ok(Some(installed_apps)) + } else { + let choices = [ + ( + bright_red!("All installed apps - {}", installed_apps.len()).to_string(), + installed_apps, + ), + ( + green!("Provided apps - {} (see command invocation)", apps.len()).to_string(), + apps, + ), + ]; + + let Some( choice_index) = dialoguer::Select::new() + .with_prompt(yellow!("You have provided apps, but also selected to cleanup all installed apps. Which collection would you like to cleanup?").to_string()) + .items(&[&choices[0].0, &choices[1].0]) + .default(1) + .interact_opt() + .map_err(|dialoguer::Error::IO(error)| error)? else { + return Ok(None); + }; + + let (_, apps) = { + let mut choices = choices; + + std::mem::replace( + &mut choices[choice_index], + const { (String::new(), Vec::new()) }, + ) + }; + + Ok(Some(apps)) + } + } else { + Ok(Some(apps)) + } +} diff --git a/src/main.rs b/src/main.rs index 99541dcd..4512502b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ mod calm_panic; mod commands; mod diagnostics; mod errors; +mod handlers; mod limits; mod logging; mod models;