Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I98240ec0f9e3932a46e79f82f32cd5d36a6a6964
156 lines
4.2 KiB
Rust
156 lines
4.2 KiB
Rust
use std::path::Path;
|
|
|
|
use crate::{
|
|
cli::RmArgs,
|
|
error::{PakkerError, Result},
|
|
model::LockFile,
|
|
ui_utils::{prompt_typo_suggestion, prompt_yes_no},
|
|
};
|
|
|
|
pub async fn execute(
|
|
args: RmArgs,
|
|
lockfile_path: &Path,
|
|
_config_path: &Path,
|
|
) -> Result<()> {
|
|
// Load expects directory path, so get parent directory
|
|
let lockfile_dir = lockfile_path.parent().unwrap_or(Path::new("."));
|
|
let mut lockfile = LockFile::load(lockfile_dir)?;
|
|
|
|
// Determine which projects to remove
|
|
let inputs: Vec<String> = if args.all {
|
|
log::info!("Removing all projects from lockfile");
|
|
lockfile
|
|
.projects
|
|
.iter()
|
|
.filter_map(|p| {
|
|
p.pakku_id
|
|
.clone()
|
|
.or_else(|| p.slug.values().next().cloned())
|
|
})
|
|
.collect()
|
|
} else {
|
|
args.inputs.clone()
|
|
};
|
|
|
|
if inputs.is_empty() {
|
|
return if args.all {
|
|
Err(PakkerError::ProjectNotFound(
|
|
"No projects found in lockfile".to_string(),
|
|
))
|
|
} else {
|
|
Err(PakkerError::ProjectNotFound(
|
|
"No projects specified".to_string(),
|
|
))
|
|
};
|
|
}
|
|
|
|
log::info!("Removing projects: {inputs:?}");
|
|
|
|
let mut removed_count = 0;
|
|
let mut removed_ids = Vec::new();
|
|
let mut projects_to_remove = Vec::new();
|
|
|
|
// Collect all known project identifiers for typo suggestions
|
|
let all_slugs: Vec<String> = lockfile
|
|
.projects
|
|
.iter()
|
|
.flat_map(|p| {
|
|
let mut ids = Vec::new();
|
|
if let Some(ref pakku_id) = p.pakku_id {
|
|
ids.push(pakku_id.clone());
|
|
}
|
|
ids.extend(p.slug.values().cloned());
|
|
ids.extend(p.name.values().cloned());
|
|
ids.extend(p.aliases.iter().cloned());
|
|
ids
|
|
})
|
|
.collect();
|
|
|
|
// First, identify all projects to remove
|
|
let mut resolved_inputs = Vec::new();
|
|
for input in &inputs {
|
|
// Find project by various identifiers
|
|
if lockfile.projects.iter().any(|p| {
|
|
p.pakku_id.as_deref() == Some(input)
|
|
|| p.slug.values().any(|s| s == input)
|
|
|| p.name.values().any(|n| n.eq_ignore_ascii_case(input))
|
|
|| p.aliases.contains(input)
|
|
}) {
|
|
resolved_inputs.push(input.clone());
|
|
} else if !args.all {
|
|
// Try typo suggestion
|
|
if let Ok(Some(suggestion)) = prompt_typo_suggestion(input, &all_slugs) {
|
|
log::info!("Using suggested project: {suggestion}");
|
|
resolved_inputs.push(suggestion);
|
|
} else {
|
|
log::warn!("Project not found: {input}");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now find the actual projects from resolved inputs
|
|
for input in &resolved_inputs {
|
|
if let Some(project) = lockfile.projects.iter().find(|p| {
|
|
p.pakku_id.as_deref() == Some(input)
|
|
|| p.slug.values().any(|s| s == input)
|
|
|| p.name.values().any(|n| n.eq_ignore_ascii_case(input))
|
|
|| p.aliases.contains(input)
|
|
}) {
|
|
projects_to_remove.push(project.get_name());
|
|
}
|
|
}
|
|
|
|
// Replace inputs with resolved_inputs for actual removal
|
|
let inputs = resolved_inputs;
|
|
|
|
if projects_to_remove.is_empty() {
|
|
return Err(PakkerError::ProjectNotFound(
|
|
"None of the specified projects found".to_string(),
|
|
));
|
|
}
|
|
|
|
// Ask for confirmation unless --yes flag is provided or --all with no
|
|
// projects
|
|
if !args.yes {
|
|
println!("The following projects will be removed:");
|
|
for name in &projects_to_remove {
|
|
println!(" - {name}");
|
|
}
|
|
|
|
if !prompt_yes_no("Do you want to continue?", false)? {
|
|
println!("Removal cancelled.");
|
|
return Ok(());
|
|
}
|
|
}
|
|
|
|
// Now actually remove the projects
|
|
for input in &inputs {
|
|
if let Some(pos) = lockfile.projects.iter().position(|p| {
|
|
p.pakku_id.as_deref() == Some(input)
|
|
|| p.slug.values().any(|s| s == input)
|
|
|| p.name.values().any(|n| n.eq_ignore_ascii_case(input))
|
|
|| p.aliases.contains(input)
|
|
}) {
|
|
let project = lockfile.projects.remove(pos);
|
|
log::info!("Removed: {}", project.get_name());
|
|
if let Some(pakku_id) = project.pakku_id.clone() {
|
|
removed_ids.push(pakku_id);
|
|
}
|
|
removed_count += 1;
|
|
}
|
|
}
|
|
|
|
// Clean up pakku_links from all remaining projects
|
|
for project in &mut lockfile.projects {
|
|
project
|
|
.pakku_links
|
|
.retain(|link| !removed_ids.contains(link));
|
|
}
|
|
|
|
// Save lockfile
|
|
lockfile.save(lockfile_dir)?;
|
|
|
|
log::info!("Successfully removed {removed_count} project(s)");
|
|
|
|
Ok(())
|
|
}
|