From c11064c3aa94dd63efd26a783a37b11decb81df4 Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 18 Mar 2026 10:49:45 +0000 Subject: [PATCH] feat(pkg): add --force flag to skip hash verification on upgrade, install, and delete When upgrading yazi across versions, the content hash computation may change, causing false "You have modified the contents" errors on packages the user never touched. This leaves users unable to upgrade, install, or delete any managed package without manually deleting each one first. Add a --force/-f flag to `ya pkg upgrade`, `ya pkg install`, and `ya pkg delete` that skips the hash_check, allowing the operation to proceed. A warning is printed when the check is skipped. The error message now also suggests --force as a remedy. Closes #2735, #3291 --- yazi-cli/src/args.rs | 16 +++++++++++++--- yazi-cli/src/main.rs | 6 +++--- yazi-cli/src/package/add.rs | 4 ++-- yazi-cli/src/package/delete.rs | 8 ++++++-- yazi-cli/src/package/deploy.rs | 8 ++++++-- yazi-cli/src/package/hash.rs | 3 ++- yazi-cli/src/package/install.rs | 4 ++-- yazi-cli/src/package/package.rs | 18 +++++++++--------- yazi-cli/src/package/upgrade.rs | 4 ++-- 9 files changed, 45 insertions(+), 26 deletions(-) diff --git a/yazi-cli/src/args.rs b/yazi-cli/src/args.rs index 591acb65..ff6a1419 100644 --- a/yazi-cli/src/args.rs +++ b/yazi-cli/src/args.rs @@ -77,17 +77,27 @@ pub(super) enum CommandPkg { Delete { /// Packages to delete. #[arg(index = 1, num_args = 1..)] - ids: Vec, + ids: Vec, + /// Force delete, skipping local modification checks. + #[arg(short, long)] + force: bool, }, /// Install all packages. - Install, + Install { + /// Force install, skipping local modification checks. + #[arg(short, long)] + force: bool, + }, /// List all packages. List, /// Upgrade all packages. Upgrade { /// Packages to upgrade, upgrade all if unspecified. #[arg(index = 1, num_args = 0..)] - ids: Vec, + ids: Vec, + /// Force upgrade, skipping local modification checks. + #[arg(short, long)] + force: bool, }, } diff --git a/yazi-cli/src/main.rs b/yazi-cli/src/main.rs index f43e9228..a10af710 100644 --- a/yazi-cli/src/main.rs +++ b/yazi-cli/src/main.rs @@ -78,10 +78,10 @@ async fn run() -> anyhow::Result<()> { let mut pkg = package::Package::load().await?; match cmd { CommandPkg::Add { ids } => pkg.add_many(&ids).await?, - CommandPkg::Delete { ids } => pkg.delete_many(&ids).await?, - CommandPkg::Install => pkg.install().await?, + CommandPkg::Delete { ids, force } => pkg.delete_many(&ids, force).await?, + CommandPkg::Install { force } => pkg.install(force).await?, CommandPkg::List => pkg.print()?, - CommandPkg::Upgrade { ids } => pkg.upgrade_many(&ids).await?, + CommandPkg::Upgrade { ids, force } => pkg.upgrade_many(&ids, force).await?, } } diff --git a/yazi-cli/src/package/add.rs b/yazi-cli/src/package/add.rs index b3d019e8..0f867b36 100644 --- a/yazi-cli/src/package/add.rs +++ b/yazi-cli/src/package/add.rs @@ -4,7 +4,7 @@ use super::{Dependency, Git}; use crate::shared::must_exists; impl Dependency { - pub(super) async fn add(&mut self) -> Result<()> { + pub(super) async fn add(&mut self, force: bool) -> Result<()> { self.header("Upgrading package `{name}`")?; let path = self.local(); @@ -14,7 +14,7 @@ impl Dependency { Git::clone(&self.remote(), &path).await?; }; - self.deploy().await?; + self.deploy(force).await?; self.rev = Git::revision(&path).await?; Ok(()) } diff --git a/yazi-cli/src/package/delete.rs b/yazi-cli/src/package/delete.rs index 4968e143..aa65dec3 100644 --- a/yazi-cli/src/package/delete.rs +++ b/yazi-cli/src/package/delete.rs @@ -6,7 +6,7 @@ use super::Dependency; use crate::shared::{maybe_exists, remove_sealed}; impl Dependency { - pub(super) async fn delete(&self) -> Result<()> { + pub(super) async fn delete(&self, force: bool) -> Result<()> { self.header("Deleting package `{name}`")?; let dir = self.target(); @@ -14,7 +14,11 @@ impl Dependency { return Ok(outln!("Not found, skipping")?); } - self.hash_check().await?; + if force { + outln!("Warning: skipping local modification check for `{}`", self.name)?; + } else { + self.hash_check().await?; + } self.delete_assets().await?; self.delete_sources().await?; diff --git a/yazi-cli/src/package/deploy.rs b/yazi-cli/src/package/deploy.rs index 2cc10ac5..3976892f 100644 --- a/yazi-cli/src/package/deploy.rs +++ b/yazi-cli/src/package/deploy.rs @@ -8,7 +8,7 @@ use super::Dependency; use crate::shared::{copy_and_seal, maybe_exists}; impl Dependency { - pub(super) async fn deploy(&mut self) -> Result<()> { + pub(super) async fn deploy(&mut self, force: bool) -> Result<()> { let from = self.local().join(&self.child); self.header("Deploying package `{name}`")?; @@ -17,7 +17,11 @@ impl Dependency { let to = self.target(); let exists = maybe_exists(&to).await; if exists { - self.hash_check().await?; + if force { + outln!("Warning: skipping local modification check for `{}`", self.name)?; + } else { + self.hash_check().await?; + } } Local::regular(&to).create_dir_all().await?; diff --git a/yazi-cli/src/package/hash.rs b/yazi-cli/src/package/hash.rs index 37fc5350..666a3209 100644 --- a/yazi-cli/src/package/hash.rs +++ b/yazi-cli/src/package/hash.rs @@ -46,7 +46,8 @@ impl Dependency { if self.hash != self.hash().await? { bail!( "You have modified the contents of the `{}` {}. For safety, the operation has been aborted. -Please manually delete it from `{}` and re-run the command.", +Please manually delete it from `{}` and re-run the command. +If you have not modified this package, re-run the command with --force to skip this check.", self.name, if self.is_flavor { "flavor" } else { "plugin" }, self.target().display() diff --git a/yazi-cli/src/package/install.rs b/yazi-cli/src/package/install.rs index 9c48e004..d03ad07f 100644 --- a/yazi-cli/src/package/install.rs +++ b/yazi-cli/src/package/install.rs @@ -4,7 +4,7 @@ use super::{Dependency, Git}; use crate::shared::must_exists; impl Dependency { - pub(super) async fn install(&mut self) -> Result<()> { + pub(super) async fn install(&mut self, force: bool) -> Result<()> { self.header("Fetching package `{name}`")?; let path = self.local(); @@ -18,7 +18,7 @@ impl Dependency { Git::checkout(&path, self.rev.trim_start_matches('=')).await?; } - self.deploy().await?; + self.deploy(force).await?; if self.rev.is_empty() { self.rev = Git::revision(&path).await?; } diff --git a/yazi-cli/src/package/package.rs b/yazi-cli/src/package/package.rs index dc654bc7..f1ebe864 100644 --- a/yazi-cli/src/package/package.rs +++ b/yazi-cli/src/package/package.rs @@ -28,19 +28,19 @@ impl Package { Ok(()) } - pub(crate) async fn delete_many(&mut self, uses: &[String]) -> Result<()> { + pub(crate) async fn delete_many(&mut self, uses: &[String], force: bool) -> Result<()> { for u in uses { - let r = self.delete(u).await; + let r = self.delete(u, force).await; self.save().await?; r?; } Ok(()) } - pub(crate) async fn install(&mut self) -> Result<()> { + pub(crate) async fn install(&mut self, force: bool) -> Result<()> { macro_rules! go { ($dep:expr) => { - let r = $dep.install().await; + let r = $dep.install(force).await; self.save().await?; r?; }; @@ -55,11 +55,11 @@ impl Package { Ok(()) } - pub(crate) async fn upgrade_many(&mut self, uses: &[String]) -> Result<()> { + pub(crate) async fn upgrade_many(&mut self, uses: &[String], force: bool) -> Result<()> { macro_rules! go { ($dep:expr) => { if uses.is_empty() || uses.contains(&$dep.r#use) { - let r = $dep.upgrade().await; + let r = $dep.upgrade(force).await; self.save().await?; r?; } @@ -107,7 +107,7 @@ impl Package { ) } - dep.add().await?; + dep.add(false).await?; if dep.is_flavor { self.flavors.push(dep); } else { @@ -116,12 +116,12 @@ impl Package { Ok(()) } - async fn delete(&mut self, r#use: &str) -> Result<()> { + async fn delete(&mut self, r#use: &str, force: bool) -> Result<()> { let Some(dep) = self.identical(&Dependency::from_str(r#use)?).cloned() else { bail!("`{}` was not found in package.toml", r#use) }; - dep.delete().await?; + dep.delete(force).await?; if dep.is_flavor { self.flavors.retain(|d| !d.identical(&dep)); } else { diff --git a/yazi-cli/src/package/upgrade.rs b/yazi-cli/src/package/upgrade.rs index a9cb8539..017e6a9a 100644 --- a/yazi-cli/src/package/upgrade.rs +++ b/yazi-cli/src/package/upgrade.rs @@ -3,7 +3,7 @@ use anyhow::Result; use super::Dependency; impl Dependency { - pub(super) async fn upgrade(&mut self) -> Result<()> { - if self.rev.starts_with('=') { Ok(()) } else { self.add().await } + pub(super) async fn upgrade(&mut self, force: bool) -> Result<()> { + if self.rev.starts_with('=') { Ok(()) } else { self.add(force).await } } }