use std::io::ErrorKind;
use std::path::PathBuf;
use tracing::log;
use crate::quilt::lineage::PackageLineage;
use crate::quilt::storage::Storage;
use crate::Error;
fn not_found_error(path: &str) -> Error {
Error::Uninstall(format!("path {} not found. Cannot uninstall.", path))
}
pub async fn uninstall_paths(
mut lineage: PackageLineage,
working_dir: PathBuf,
storage: &impl Storage,
paths: &Vec<String>,
) -> Result<PackageLineage, Error> {
log::debug!("Uninstalling paths {:?}", paths);
for path in paths {
lineage.paths.remove(path).ok_or(not_found_error(path))?;
let working_path = working_dir.join(path);
if let Err(err) = storage.remove_file(working_path).await {
if err.kind() != ErrorKind::NotFound {
return Err(Error::Io(err));
}
}
}
Ok(lineage)
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::BTreeMap;
use crate::quilt::mocks;
use crate::quilt::storage::mock_storage::MockStorage;
#[tokio::test]
async fn uninstall_not_installed_path() -> Result<(), Error> {
let storage = MockStorage::default();
let lineage = PackageLineage::default();
let paths = vec!["test folde/r".to_string()];
let modified_lineage = uninstall_paths(lineage, PathBuf::new(), &storage, &paths).await;
assert_eq!(
modified_lineage.unwrap_err().to_string(),
"Uninstall error: path test folde/r not found. Cannot uninstall."
);
Ok(())
}
#[tokio::test]
async fn uninstall_single_path() -> Result<(), Error> {
let installed_paths = vec!["a/a", "test folde/r", "b/b"];
let lineage = mocks::lineage::with_paths(&installed_paths);
let storage = MockStorage::default();
storage
.write_file(PathBuf::from("a/a"), &Vec::new())
.await?;
storage
.write_file(PathBuf::from("test folde/r"), &Vec::new())
.await?;
storage
.write_file(PathBuf::from("b/b"), &Vec::new())
.await?;
let paths_to_uninstall = vec!["test folde/r".to_string()];
let key = PathBuf::from("test folde/r");
assert!(storage.exists(&key).await);
let modified_lineage =
uninstall_paths(lineage, PathBuf::new(), &storage, &paths_to_uninstall).await?;
assert!(!storage.exists(&key).await);
assert_eq!(
modified_lineage.paths,
BTreeMap::from([
("a/a".to_string(), mocks::lineage::path_state()),
("b/b".to_string(), mocks::lineage::path_state()),
])
);
Ok(())
}
#[tokio::test]
async fn uninstall_multiple_paths() -> Result<(), Error> {
let lineage = mocks::lineage::with_paths(&vec!["a/a", "b/b"]);
let paths = vec!["b/b".to_string(), "a/a".to_string()];
let storage = MockStorage::default();
let modified_lineage = uninstall_paths(lineage, PathBuf::new(), &storage, &paths).await?;
assert!(modified_lineage.paths.is_empty());
Ok(())
}
}