From 0dbce06a6e03da2f93d323449a76f0c6e9ea18e9 Mon Sep 17 00:00:00 2001 From: Valter Santos Date: Thu, 9 Jan 2025 16:09:54 +1300 Subject: [PATCH] feat: delete/uninstall packages --- yazi-cli/src/args.rs | 3 +++ yazi-cli/src/main.rs | 2 ++ yazi-cli/src/package/delete.rs | 26 +++++++++++++++++++++++ yazi-cli/src/package/dependency.rs | 9 ++++++++ yazi-cli/src/package/deploy.rs | 9 +++----- yazi-cli/src/package/hash.rs | 8 ++------ yazi-cli/src/package/mod.rs | 2 +- yazi-cli/src/package/package.rs | 33 +++++++++++++++++++++++++----- 8 files changed, 74 insertions(+), 18 deletions(-) create mode 100644 yazi-cli/src/package/delete.rs diff --git a/yazi-cli/src/args.rs b/yazi-cli/src/args.rs index b74082ee..c309e201 100644 --- a/yazi-cli/src/args.rs +++ b/yazi-cli/src/args.rs @@ -57,6 +57,9 @@ pub(super) struct CommandPack { /// Add a package. #[arg(short = 'a', long)] pub(super) add: Option, + /// Delete a package. + #[arg(short = 'd', long)] + pub(super) delete: Option, /// Install all packages. #[arg(short = 'i', long)] pub(super) install: bool, diff --git a/yazi-cli/src/main.rs b/yazi-cli/src/main.rs index 168f7f7c..e1470017 100644 --- a/yazi-cli/src/main.rs +++ b/yazi-cli/src/main.rs @@ -73,6 +73,8 @@ async fn run() -> anyhow::Result<()> { package::Package::load().await?.install(true).await?; } else if let Some(repo) = cmd.add { package::Package::load().await?.add(&repo).await?; + } else if let Some(repo) = cmd.delete { + package::Package::load().await?.delete(&repo).await?; } } diff --git a/yazi-cli/src/package/delete.rs b/yazi-cli/src/package/delete.rs new file mode 100644 index 00000000..ec35eb5f --- /dev/null +++ b/yazi-cli/src/package/delete.rs @@ -0,0 +1,26 @@ +use anyhow::{Result, bail}; +use tokio::fs; +use yazi_fs::must_exists; +use yazi_macro::outln; + +use super::Dependency; + +impl Dependency { + pub(super) async fn delete(&self) -> Result<()> { + self.header("Deleting package `{name}`")?; + + let path = self.deployed_directory(); + + if must_exists(&path).await { + fs::remove_dir_all(&path).await?; + } else { + bail!( + "The package.toml file states that `{}` exists, but the directory was not found. The entry will be removed from package.toml.", + self.name + ); + } + + outln!("Done!")?; + Ok(()) + } +} diff --git a/yazi-cli/src/package/dependency.rs b/yazi-cli/src/package/dependency.rs index 78e2b5a5..0ecc717f 100644 --- a/yazi-cli/src/package/dependency.rs +++ b/yazi-cli/src/package/dependency.rs @@ -27,6 +27,15 @@ impl Dependency { .join(format!("{:x}", XxHash3_128::oneshot(self.remote().as_bytes()))) } + #[inline] + pub(super) fn deployed_directory(&self) -> PathBuf { + return if self.is_flavor { + Xdg::config_dir().join(format!("flavors/{}", self.name)) + } else { + Xdg::config_dir().join(format!("plugins/{}", self.name)) + }; + } + #[inline] pub(super) fn remote(&self) -> String { // Support more Git hosting services in the future diff --git a/yazi-cli/src/package/deploy.rs b/yazi-cli/src/package/deploy.rs index 1f4469e2..b9a8da5c 100644 --- a/yazi-cli/src/package/deploy.rs +++ b/yazi-cli/src/package/deploy.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use anyhow::{Context, Result, bail}; use tokio::fs; -use yazi_fs::{Xdg, copy_and_seal, maybe_exists, remove_dir_clean}; +use yazi_fs::{copy_and_seal, maybe_exists, remove_dir_clean}; use yazi_macro::outln; use super::Dependency; @@ -13,11 +13,8 @@ impl Dependency { self.header("Deploying package `{name}`")?; self.is_flavor = maybe_exists(&from.join("flavor.toml")).await; - let to = if self.is_flavor { - Xdg::config_dir().join(format!("flavors/{}", self.name)) - } else { - Xdg::config_dir().join(format!("plugins/{}", self.name)) - }; + + let to = self.deployed_directory(); if maybe_exists(&to).await && self.hash != self.hash().await? { bail!( diff --git a/yazi-cli/src/package/hash.rs b/yazi-cli/src/package/hash.rs index 2cf97c60..3ccc0da5 100644 --- a/yazi-cli/src/package/hash.rs +++ b/yazi-cli/src/package/hash.rs @@ -1,17 +1,13 @@ use anyhow::{Context, Result}; use tokio::fs; use twox_hash::XxHash3_128; -use yazi_fs::{Xdg, ok_or_not_found}; +use yazi_fs::ok_or_not_found; use super::Dependency; impl Dependency { pub(crate) async fn hash(&self) -> Result { - let dir = if self.is_flavor { - Xdg::config_dir().join(format!("flavors/{}", self.name)) - } else { - Xdg::config_dir().join(format!("plugins/{}", self.name)) - }; + let dir = self.deployed_directory(); let files = if self.is_flavor { &[ diff --git a/yazi-cli/src/package/mod.rs b/yazi-cli/src/package/mod.rs index 3328a374..7dde8fb2 100644 --- a/yazi-cli/src/package/mod.rs +++ b/yazi-cli/src/package/mod.rs @@ -1,6 +1,6 @@ #![allow(clippy::module_inception)] -yazi_macro::mod_flat!(add dependency deploy git hash install package upgrade); +yazi_macro::mod_flat!(add delete dependency deploy git hash install package upgrade); use anyhow::Context; use yazi_fs::Xdg; diff --git a/yazi-cli/src/package/package.rs b/yazi-cli/src/package/package.rs index f6d503de..ff626754 100644 --- a/yazi-cli/src/package/package.rs +++ b/yazi-cli/src/package/package.rs @@ -25,11 +25,10 @@ impl Package { pub(crate) async fn add(&mut self, use_: &str) -> Result<()> { let mut dep = Dependency::from_str(use_)?; - if self.plugins.iter().any(|d| d.parent == dep.parent && d.child == dep.child) { - bail!("Plugin `{}` already exists in package.toml", dep.name); - } - if self.flavors.iter().any(|d| d.parent == dep.parent && d.child == dep.child) { - bail!("Flavor `{}` already exists in package.toml", dep.name); + + if let Some(existing_dep) = self.find_dep_in_package(&dep) { + let package_type = if existing_dep.is_flavor { "Flavor" } else { "Plugin" }; + bail!("{} `{}` already exists in package.toml", package_type, dep.name) } dep.add().await?; @@ -43,6 +42,25 @@ impl Package { create_and_seal(&Self::toml(), s.as_bytes()).await.context("Failed to write package.toml") } + pub(crate) async fn delete(&mut self, use_: &str) -> Result<()> { + let dep_to_find = Dependency::from_str(use_)?; + + let dep = match self.find_dep_in_package(&dep_to_find) { + Some(d) => d, + None => bail!("`{}` was not found in package.toml", use_), + }; + + dep.delete().await?; + if dep.is_flavor { + self.flavors.retain(|f| f.use_ != use_); + } else { + self.plugins.retain(|f| f.use_ != use_); + } + + let s = toml::to_string_pretty(self)?; + create_and_seal(&Self::toml(), s.as_bytes()).await.context("Failed to write package.toml") + } + pub(crate) async fn install(&mut self, upgrade: bool) -> Result<()> { for d in &mut self.plugins { if upgrade { @@ -165,6 +183,11 @@ impl Package { create_and_seal(&Self::toml(), s.as_bytes()).await.context("Failed to write package.toml") } + #[inline] + fn find_dep_in_package(&self, dep: &Dependency) -> Option<&Dependency> { + return self.plugins.iter().chain(self.flavors.iter()).find(|d| d.use_ == dep.use_); + } + #[inline] fn toml() -> PathBuf { Xdg::config_dir().join("package.toml") } }