mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
fix: ensure state synchronization even when the package update fails midway (#2613)
This commit is contained in:
parent
af92b92da8
commit
d2cc73c927
7 changed files with 98 additions and 93 deletions
|
|
@ -8,13 +8,13 @@ impl Dependency {
|
|||
self.header("Upgrading package `{name}`")?;
|
||||
|
||||
let path = self.local();
|
||||
if !must_exists(&path).await {
|
||||
Git::clone(&self.remote(), &path).await?;
|
||||
} else {
|
||||
if must_exists(&path).await {
|
||||
Git::pull(&path).await?;
|
||||
} else {
|
||||
Git::clone(&self.remote(), &path).await?;
|
||||
};
|
||||
|
||||
self.rev = Git::hash(&path).await?;
|
||||
self.rev = Git::revision(&path).await?;
|
||||
self.deploy().await
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use anyhow::{Context, Result, bail};
|
||||
use anyhow::{Context, Result};
|
||||
use tokio::fs;
|
||||
use yazi_fs::{maybe_exists, ok_or_not_found, remove_dir_clean, remove_sealed};
|
||||
use yazi_macro::outln;
|
||||
|
|
@ -14,36 +14,9 @@ impl Dependency {
|
|||
return Ok(outln!("Not found, skipping")?);
|
||||
}
|
||||
|
||||
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: {}",
|
||||
self.name,
|
||||
if self.is_flavor { "flavor" } else { "plugin" },
|
||||
dir.display()
|
||||
);
|
||||
}
|
||||
|
||||
let files = if self.is_flavor {
|
||||
&["flavor.toml", "tmtheme.xml", "README.md", "preview.png", "LICENSE", "LICENSE-tmtheme"][..]
|
||||
} else {
|
||||
&["main.lua", "README.md", "LICENSE"][..]
|
||||
};
|
||||
for p in files.iter().map(|&f| dir.join(f)) {
|
||||
ok_or_not_found(remove_sealed(&p).await)
|
||||
.with_context(|| format!("failed to delete `{}`", p.display()))?;
|
||||
}
|
||||
|
||||
self.hash_check().await?;
|
||||
self.delete_assets().await?;
|
||||
if ok_or_not_found(fs::remove_dir(&dir).await).is_ok() {
|
||||
outln!("Done!")?;
|
||||
} else {
|
||||
outln!(
|
||||
"Done!
|
||||
For safety, user data has been preserved, please manually delete them within: {}",
|
||||
dir.display()
|
||||
)?;
|
||||
}
|
||||
self.delete_sources().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -65,4 +38,29 @@ For safety, user data has been preserved, please manually delete them within: {}
|
|||
remove_dir_clean(&assets).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) async fn delete_sources(&self) -> Result<()> {
|
||||
let dir = self.target();
|
||||
let files = if self.is_flavor {
|
||||
&["flavor.toml", "tmtheme.xml", "README.md", "preview.png", "LICENSE", "LICENSE-tmtheme"][..]
|
||||
} else {
|
||||
&["main.lua", "README.md", "LICENSE"][..]
|
||||
};
|
||||
|
||||
for p in files.iter().map(|&f| dir.join(f)) {
|
||||
ok_or_not_found(remove_sealed(&p).await)
|
||||
.with_context(|| format!("failed to delete `{}`", p.display()))?;
|
||||
}
|
||||
|
||||
if ok_or_not_found(fs::remove_dir(&dir).await).is_ok() {
|
||||
outln!("Done!")?;
|
||||
} else {
|
||||
outln!(
|
||||
"Done!
|
||||
For safety, user data has been preserved, please manually delete them within: {}",
|
||||
dir.display()
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::{Context, Result, bail};
|
||||
use anyhow::{Context, Result};
|
||||
use tokio::fs;
|
||||
use yazi_fs::{copy_and_seal, maybe_exists, remove_dir_clean};
|
||||
use yazi_macro::outln;
|
||||
|
|
@ -15,44 +15,27 @@ impl Dependency {
|
|||
self.is_flavor = maybe_exists(&from.join("flavor.toml")).await;
|
||||
|
||||
let to = self.target();
|
||||
if maybe_exists(&to).await && 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.",
|
||||
self.name,
|
||||
if self.is_flavor { "flavor" } else { "plugin" },
|
||||
to.display()
|
||||
);
|
||||
let exists = maybe_exists(&to).await;
|
||||
if exists {
|
||||
self.hash_check().await?;
|
||||
}
|
||||
|
||||
fs::create_dir_all(&to).await?;
|
||||
if let Err(e) = Self::deploy_sources(&from, &to, self.is_flavor).await {
|
||||
remove_dir_clean(&to).await;
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
self.delete_assets().await?;
|
||||
Self::deploy_assets(from.join("assets"), to.join("assets")).await?;
|
||||
|
||||
self.hash = self.hash().await?;
|
||||
outln!("Done!")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn deploy_sources(from: &Path, to: &Path, is_flavor: bool) -> Result<()> {
|
||||
let files = if is_flavor {
|
||||
&["flavor.toml", "tmtheme.xml", "README.md", "preview.png", "LICENSE", "LICENSE-tmtheme"][..]
|
||||
} else {
|
||||
&["main.lua", "README.md", "LICENSE"][..]
|
||||
};
|
||||
|
||||
for file in files {
|
||||
let (from, to) = (from.join(file), to.join(file));
|
||||
copy_and_seal(&from, &to)
|
||||
.await
|
||||
.with_context(|| format!("failed to copy `{}` to `{}`", from.display(), to.display()))?;
|
||||
let res1 = Self::deploy_assets(from.join("assets"), to.join("assets")).await;
|
||||
let res2 = Self::deploy_sources(&from, &to, self.is_flavor).await;
|
||||
if !exists && (res2.is_err() || res1.is_err()) {
|
||||
self.delete_assets().await?;
|
||||
self.delete_sources().await?;
|
||||
}
|
||||
|
||||
remove_dir_clean(&to).await;
|
||||
self.hash = self.hash().await?;
|
||||
res2?;
|
||||
res1?;
|
||||
|
||||
outln!("Done!")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -72,4 +55,20 @@ Please manually delete it from `{}` and re-run the command.",
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn deploy_sources(from: &Path, to: &Path, is_flavor: bool) -> Result<()> {
|
||||
let files = if is_flavor {
|
||||
&["flavor.toml", "tmtheme.xml", "README.md", "preview.png", "LICENSE", "LICENSE-tmtheme"][..]
|
||||
} else {
|
||||
&["main.lua", "README.md", "LICENSE"][..]
|
||||
};
|
||||
|
||||
for file in files {
|
||||
let (from, to) = (from.join(file), to.join(file));
|
||||
copy_and_seal(&from, &to)
|
||||
.await
|
||||
.with_context(|| format!("failed to copy `{}` to `{}`", from.display(), to.display()))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ impl Git {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) async fn hash(path: &Path) -> Result<String> {
|
||||
pub(super) async fn revision(path: &Path) -> Result<String> {
|
||||
let output = Command::new("git")
|
||||
.args(["rev-parse", "--short", "HEAD"])
|
||||
.current_dir(path)
|
||||
|
|
|
|||
|
|
@ -52,4 +52,17 @@ impl Dependency {
|
|||
|
||||
Ok(format!("{:x}", h.finish_128()))
|
||||
}
|
||||
|
||||
pub(super) async fn hash_check(&self) -> Result<()> {
|
||||
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.",
|
||||
self.name,
|
||||
if self.is_flavor { "flavor" } else { "plugin" },
|
||||
self.target().display()
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ impl Dependency {
|
|||
};
|
||||
|
||||
if self.rev.is_empty() {
|
||||
self.rev = Git::hash(&path).await?;
|
||||
self.rev = Git::revision(&path).await?;
|
||||
} else {
|
||||
Git::checkout(&path, self.rev.trim_start_matches('=')).await?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,41 +25,36 @@ impl Package {
|
|||
|
||||
pub(crate) async fn add_many(&mut self, uses: &[String]) -> Result<()> {
|
||||
for u in uses {
|
||||
if let Err(e) = self.add(u).await {
|
||||
self.save().await?;
|
||||
return Err(e);
|
||||
}
|
||||
let r = self.add(u).await;
|
||||
self.save().await?;
|
||||
r?;
|
||||
}
|
||||
self.save().await
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn delete_many(&mut self, uses: &[String]) -> Result<()> {
|
||||
for u in uses {
|
||||
if let Err(e) = self.delete(u).await {
|
||||
self.save().await?;
|
||||
return Err(e);
|
||||
}
|
||||
let r = self.delete(u).await;
|
||||
self.save().await?;
|
||||
r?;
|
||||
}
|
||||
self.save().await
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn install(&mut self, upgrade: bool) -> Result<()> {
|
||||
for d in &mut self.plugins {
|
||||
if upgrade {
|
||||
d.upgrade().await?;
|
||||
} else {
|
||||
d.install().await?;
|
||||
}
|
||||
for i in 0..self.plugins.len() {
|
||||
let r =
|
||||
if upgrade { self.plugins[i].upgrade().await } else { self.plugins[i].install().await };
|
||||
self.save().await?;
|
||||
r?;
|
||||
}
|
||||
for d in &mut self.flavors {
|
||||
if upgrade {
|
||||
d.upgrade().await?;
|
||||
} else {
|
||||
d.install().await?;
|
||||
}
|
||||
for i in 0..self.flavors.len() {
|
||||
let r =
|
||||
if upgrade { self.flavors[i].upgrade().await } else { self.flavors[i].install().await };
|
||||
self.save().await?;
|
||||
r?;
|
||||
}
|
||||
|
||||
self.save().await
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn print(&self) -> Result<()> {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue