mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
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
This commit is contained in:
parent
a246e9c7c0
commit
c11064c3aa
9 changed files with 45 additions and 26 deletions
|
|
@ -77,17 +77,27 @@ pub(super) enum CommandPkg {
|
||||||
Delete {
|
Delete {
|
||||||
/// Packages to delete.
|
/// Packages to delete.
|
||||||
#[arg(index = 1, num_args = 1..)]
|
#[arg(index = 1, num_args = 1..)]
|
||||||
ids: Vec<String>,
|
ids: Vec<String>,
|
||||||
|
/// Force delete, skipping local modification checks.
|
||||||
|
#[arg(short, long)]
|
||||||
|
force: bool,
|
||||||
},
|
},
|
||||||
/// Install all packages.
|
/// Install all packages.
|
||||||
Install,
|
Install {
|
||||||
|
/// Force install, skipping local modification checks.
|
||||||
|
#[arg(short, long)]
|
||||||
|
force: bool,
|
||||||
|
},
|
||||||
/// List all packages.
|
/// List all packages.
|
||||||
List,
|
List,
|
||||||
/// Upgrade all packages.
|
/// Upgrade all packages.
|
||||||
Upgrade {
|
Upgrade {
|
||||||
/// Packages to upgrade, upgrade all if unspecified.
|
/// Packages to upgrade, upgrade all if unspecified.
|
||||||
#[arg(index = 1, num_args = 0..)]
|
#[arg(index = 1, num_args = 0..)]
|
||||||
ids: Vec<String>,
|
ids: Vec<String>,
|
||||||
|
/// Force upgrade, skipping local modification checks.
|
||||||
|
#[arg(short, long)]
|
||||||
|
force: bool,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,10 +78,10 @@ async fn run() -> anyhow::Result<()> {
|
||||||
let mut pkg = package::Package::load().await?;
|
let mut pkg = package::Package::load().await?;
|
||||||
match cmd {
|
match cmd {
|
||||||
CommandPkg::Add { ids } => pkg.add_many(&ids).await?,
|
CommandPkg::Add { ids } => pkg.add_many(&ids).await?,
|
||||||
CommandPkg::Delete { ids } => pkg.delete_many(&ids).await?,
|
CommandPkg::Delete { ids, force } => pkg.delete_many(&ids, force).await?,
|
||||||
CommandPkg::Install => pkg.install().await?,
|
CommandPkg::Install { force } => pkg.install(force).await?,
|
||||||
CommandPkg::List => pkg.print()?,
|
CommandPkg::List => pkg.print()?,
|
||||||
CommandPkg::Upgrade { ids } => pkg.upgrade_many(&ids).await?,
|
CommandPkg::Upgrade { ids, force } => pkg.upgrade_many(&ids, force).await?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use super::{Dependency, Git};
|
||||||
use crate::shared::must_exists;
|
use crate::shared::must_exists;
|
||||||
|
|
||||||
impl Dependency {
|
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}`")?;
|
self.header("Upgrading package `{name}`")?;
|
||||||
|
|
||||||
let path = self.local();
|
let path = self.local();
|
||||||
|
|
@ -14,7 +14,7 @@ impl Dependency {
|
||||||
Git::clone(&self.remote(), &path).await?;
|
Git::clone(&self.remote(), &path).await?;
|
||||||
};
|
};
|
||||||
|
|
||||||
self.deploy().await?;
|
self.deploy(force).await?;
|
||||||
self.rev = Git::revision(&path).await?;
|
self.rev = Git::revision(&path).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use super::Dependency;
|
||||||
use crate::shared::{maybe_exists, remove_sealed};
|
use crate::shared::{maybe_exists, remove_sealed};
|
||||||
|
|
||||||
impl Dependency {
|
impl Dependency {
|
||||||
pub(super) async fn delete(&self) -> Result<()> {
|
pub(super) async fn delete(&self, force: bool) -> Result<()> {
|
||||||
self.header("Deleting package `{name}`")?;
|
self.header("Deleting package `{name}`")?;
|
||||||
|
|
||||||
let dir = self.target();
|
let dir = self.target();
|
||||||
|
|
@ -14,7 +14,11 @@ impl Dependency {
|
||||||
return Ok(outln!("Not found, skipping")?);
|
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_assets().await?;
|
||||||
self.delete_sources().await?;
|
self.delete_sources().await?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use super::Dependency;
|
||||||
use crate::shared::{copy_and_seal, maybe_exists};
|
use crate::shared::{copy_and_seal, maybe_exists};
|
||||||
|
|
||||||
impl Dependency {
|
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);
|
let from = self.local().join(&self.child);
|
||||||
|
|
||||||
self.header("Deploying package `{name}`")?;
|
self.header("Deploying package `{name}`")?;
|
||||||
|
|
@ -17,7 +17,11 @@ impl Dependency {
|
||||||
let to = self.target();
|
let to = self.target();
|
||||||
let exists = maybe_exists(&to).await;
|
let exists = maybe_exists(&to).await;
|
||||||
if exists {
|
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?;
|
Local::regular(&to).create_dir_all().await?;
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,8 @@ impl Dependency {
|
||||||
if self.hash != self.hash().await? {
|
if self.hash != self.hash().await? {
|
||||||
bail!(
|
bail!(
|
||||||
"You have modified the contents of the `{}` {}. For safety, the operation has been aborted.
|
"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,
|
self.name,
|
||||||
if self.is_flavor { "flavor" } else { "plugin" },
|
if self.is_flavor { "flavor" } else { "plugin" },
|
||||||
self.target().display()
|
self.target().display()
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use super::{Dependency, Git};
|
||||||
use crate::shared::must_exists;
|
use crate::shared::must_exists;
|
||||||
|
|
||||||
impl Dependency {
|
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}`")?;
|
self.header("Fetching package `{name}`")?;
|
||||||
|
|
||||||
let path = self.local();
|
let path = self.local();
|
||||||
|
|
@ -18,7 +18,7 @@ impl Dependency {
|
||||||
Git::checkout(&path, self.rev.trim_start_matches('=')).await?;
|
Git::checkout(&path, self.rev.trim_start_matches('=')).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.deploy().await?;
|
self.deploy(force).await?;
|
||||||
if self.rev.is_empty() {
|
if self.rev.is_empty() {
|
||||||
self.rev = Git::revision(&path).await?;
|
self.rev = Git::revision(&path).await?;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,19 +28,19 @@ impl Package {
|
||||||
Ok(())
|
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 {
|
for u in uses {
|
||||||
let r = self.delete(u).await;
|
let r = self.delete(u, force).await;
|
||||||
self.save().await?;
|
self.save().await?;
|
||||||
r?;
|
r?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn install(&mut self) -> Result<()> {
|
pub(crate) async fn install(&mut self, force: bool) -> Result<()> {
|
||||||
macro_rules! go {
|
macro_rules! go {
|
||||||
($dep:expr) => {
|
($dep:expr) => {
|
||||||
let r = $dep.install().await;
|
let r = $dep.install(force).await;
|
||||||
self.save().await?;
|
self.save().await?;
|
||||||
r?;
|
r?;
|
||||||
};
|
};
|
||||||
|
|
@ -55,11 +55,11 @@ impl Package {
|
||||||
Ok(())
|
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 {
|
macro_rules! go {
|
||||||
($dep:expr) => {
|
($dep:expr) => {
|
||||||
if uses.is_empty() || uses.contains(&$dep.r#use) {
|
if uses.is_empty() || uses.contains(&$dep.r#use) {
|
||||||
let r = $dep.upgrade().await;
|
let r = $dep.upgrade(force).await;
|
||||||
self.save().await?;
|
self.save().await?;
|
||||||
r?;
|
r?;
|
||||||
}
|
}
|
||||||
|
|
@ -107,7 +107,7 @@ impl Package {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
dep.add().await?;
|
dep.add(false).await?;
|
||||||
if dep.is_flavor {
|
if dep.is_flavor {
|
||||||
self.flavors.push(dep);
|
self.flavors.push(dep);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -116,12 +116,12 @@ impl Package {
|
||||||
Ok(())
|
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 {
|
let Some(dep) = self.identical(&Dependency::from_str(r#use)?).cloned() else {
|
||||||
bail!("`{}` was not found in package.toml", r#use)
|
bail!("`{}` was not found in package.toml", r#use)
|
||||||
};
|
};
|
||||||
|
|
||||||
dep.delete().await?;
|
dep.delete(force).await?;
|
||||||
if dep.is_flavor {
|
if dep.is_flavor {
|
||||||
self.flavors.retain(|d| !d.identical(&dep));
|
self.flavors.retain(|d| !d.identical(&dep));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use anyhow::Result;
|
||||||
use super::Dependency;
|
use super::Dependency;
|
||||||
|
|
||||||
impl Dependency {
|
impl Dependency {
|
||||||
pub(super) async fn upgrade(&mut self) -> Result<()> {
|
pub(super) async fn upgrade(&mut self, force: bool) -> Result<()> {
|
||||||
if self.rev.starts_with('=') { Ok(()) } else { self.add().await }
|
if self.rev.starts_with('=') { Ok(()) } else { self.add(force).await }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue