use super::super::lockfile::{load_lockfile, lockfile_path, save_lockfile};
use super::super::manifest;
use super::super::path::ContainedPath;
use super::super::project::resolve_project_root;
use super::super::resolve::packages_dir;
use super::super::AppService;
impl AppService {
pub async fn pkg_remove(
&self,
name: &str,
project_root: Option<String>,
scope: Option<String>,
) -> Result<String, String> {
let effective_scope =
determine_remove_scope(name, project_root.as_deref(), scope.as_deref());
match effective_scope {
RemoveScope::Project(root) => {
let mut lock = match load_lockfile(&root)? {
Some(l) => l,
None => {
return Err(format!(
"Package '{name}' not found in project (no alc.lock at {})",
root.display()
));
}
};
let before = lock.packages.len();
lock.packages.retain(|p| p.name != name);
if lock.packages.len() == before {
return Err(format!(
"Package '{name}' not found in alc.lock at {}",
root.display()
));
}
save_lockfile(&root, &lock)?;
Ok(serde_json::json!({
"removed": name,
"scope": "project",
"lockfile": lockfile_path(&root).display().to_string(),
})
.to_string())
}
RemoveScope::Global => {
let pkg_dir = packages_dir()?;
let dest = ContainedPath::child(&pkg_dir, name)?;
if !dest.as_ref().exists() {
return Err(format!("Package '{name}' not found"));
}
std::fs::remove_dir_all(&dest)
.map_err(|e| format!("Failed to remove '{name}': {e}"))?;
let _ = manifest::record_remove(name);
Ok(serde_json::json!({ "removed": name, "scope": "global" }).to_string())
}
}
}
}
enum RemoveScope {
Project(std::path::PathBuf),
Global,
}
fn determine_remove_scope(
name: &str,
project_root: Option<&str>,
scope: Option<&str>,
) -> RemoveScope {
if scope == Some("global") {
return RemoveScope::Global;
}
let root = match resolve_project_root(project_root) {
Some(r) => r,
None => return RemoveScope::Global,
};
if project_root.is_some() {
return RemoveScope::Project(root);
}
if scope == Some("project") {
return RemoveScope::Project(root);
}
match load_lockfile(&root) {
Ok(Some(lock)) if lock.packages.iter().any(|p| p.name == name) => {
RemoveScope::Project(root)
}
_ => RemoveScope::Global,
}
}