mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41: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}`")?;
|
self.header("Upgrading package `{name}`")?;
|
||||||
|
|
||||||
let path = self.local();
|
let path = self.local();
|
||||||
if !must_exists(&path).await {
|
if must_exists(&path).await {
|
||||||
Git::clone(&self.remote(), &path).await?;
|
|
||||||
} else {
|
|
||||||
Git::pull(&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
|
self.deploy().await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use anyhow::{Context, Result, bail};
|
use anyhow::{Context, Result};
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
use yazi_fs::{maybe_exists, ok_or_not_found, remove_dir_clean, remove_sealed};
|
use yazi_fs::{maybe_exists, ok_or_not_found, remove_dir_clean, remove_sealed};
|
||||||
use yazi_macro::outln;
|
use yazi_macro::outln;
|
||||||
|
|
@ -14,36 +14,9 @@ impl Dependency {
|
||||||
return Ok(outln!("Not found, skipping")?);
|
return Ok(outln!("Not found, skipping")?);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.hash != self.hash().await? {
|
self.hash_check().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.delete_assets().await?;
|
self.delete_assets().await?;
|
||||||
if ok_or_not_found(fs::remove_dir(&dir).await).is_ok() {
|
self.delete_sources().await?;
|
||||||
outln!("Done!")?;
|
|
||||||
} else {
|
|
||||||
outln!(
|
|
||||||
"Done!
|
|
||||||
For safety, user data has been preserved, please manually delete them within: {}",
|
|
||||||
dir.display()
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -65,4 +38,29 @@ For safety, user data has been preserved, please manually delete them within: {}
|
||||||
remove_dir_clean(&assets).await;
|
remove_dir_clean(&assets).await;
|
||||||
Ok(())
|
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 std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use anyhow::{Context, Result, bail};
|
use anyhow::{Context, Result};
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
use yazi_fs::{copy_and_seal, maybe_exists, remove_dir_clean};
|
use yazi_fs::{copy_and_seal, maybe_exists, remove_dir_clean};
|
||||||
use yazi_macro::outln;
|
use yazi_macro::outln;
|
||||||
|
|
@ -15,44 +15,27 @@ impl Dependency {
|
||||||
self.is_flavor = maybe_exists(&from.join("flavor.toml")).await;
|
self.is_flavor = maybe_exists(&from.join("flavor.toml")).await;
|
||||||
|
|
||||||
let to = self.target();
|
let to = self.target();
|
||||||
if maybe_exists(&to).await && self.hash != self.hash().await? {
|
let exists = maybe_exists(&to).await;
|
||||||
bail!(
|
if exists {
|
||||||
"You have modified the contents of the `{}` {}. For safety, the operation has been aborted.
|
self.hash_check().await?;
|
||||||
Please manually delete it from `{}` and re-run the command.",
|
|
||||||
self.name,
|
|
||||||
if self.is_flavor { "flavor" } else { "plugin" },
|
|
||||||
to.display()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::create_dir_all(&to).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.delete_assets().await?;
|
||||||
Self::deploy_assets(from.join("assets"), to.join("assets")).await?;
|
|
||||||
|
|
||||||
self.hash = self.hash().await?;
|
let res1 = Self::deploy_assets(from.join("assets"), to.join("assets")).await;
|
||||||
outln!("Done!")?;
|
let res2 = Self::deploy_sources(&from, &to, self.is_flavor).await;
|
||||||
|
if !exists && (res2.is_err() || res1.is_err()) {
|
||||||
Ok(())
|
self.delete_assets().await?;
|
||||||
}
|
self.delete_sources().await?;
|
||||||
|
|
||||||
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()))?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
remove_dir_clean(&to).await;
|
||||||
|
self.hash = self.hash().await?;
|
||||||
|
res2?;
|
||||||
|
res1?;
|
||||||
|
|
||||||
|
outln!("Done!")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,4 +55,20 @@ Please manually delete it from `{}` and re-run the command.",
|
||||||
}
|
}
|
||||||
Ok(())
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn hash(path: &Path) -> Result<String> {
|
pub(super) async fn revision(path: &Path) -> Result<String> {
|
||||||
let output = Command::new("git")
|
let output = Command::new("git")
|
||||||
.args(["rev-parse", "--short", "HEAD"])
|
.args(["rev-parse", "--short", "HEAD"])
|
||||||
.current_dir(path)
|
.current_dir(path)
|
||||||
|
|
|
||||||
|
|
@ -52,4 +52,17 @@ impl Dependency {
|
||||||
|
|
||||||
Ok(format!("{:x}", h.finish_128()))
|
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() {
|
if self.rev.is_empty() {
|
||||||
self.rev = Git::hash(&path).await?;
|
self.rev = Git::revision(&path).await?;
|
||||||
} else {
|
} else {
|
||||||
Git::checkout(&path, self.rev.trim_start_matches('=')).await?;
|
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<()> {
|
pub(crate) async fn add_many(&mut self, uses: &[String]) -> Result<()> {
|
||||||
for u in uses {
|
for u in uses {
|
||||||
if let Err(e) = self.add(u).await {
|
let r = self.add(u).await;
|
||||||
self.save().await?;
|
self.save().await?;
|
||||||
return Err(e);
|
r?;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.save().await
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn delete_many(&mut self, uses: &[String]) -> Result<()> {
|
pub(crate) async fn delete_many(&mut self, uses: &[String]) -> Result<()> {
|
||||||
for u in uses {
|
for u in uses {
|
||||||
if let Err(e) = self.delete(u).await {
|
let r = self.delete(u).await;
|
||||||
self.save().await?;
|
self.save().await?;
|
||||||
return Err(e);
|
r?;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.save().await
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn install(&mut self, upgrade: bool) -> Result<()> {
|
pub(crate) async fn install(&mut self, upgrade: bool) -> Result<()> {
|
||||||
for d in &mut self.plugins {
|
for i in 0..self.plugins.len() {
|
||||||
if upgrade {
|
let r =
|
||||||
d.upgrade().await?;
|
if upgrade { self.plugins[i].upgrade().await } else { self.plugins[i].install().await };
|
||||||
} else {
|
self.save().await?;
|
||||||
d.install().await?;
|
r?;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for d in &mut self.flavors {
|
for i in 0..self.flavors.len() {
|
||||||
if upgrade {
|
let r =
|
||||||
d.upgrade().await?;
|
if upgrade { self.flavors[i].upgrade().await } else { self.flavors[i].install().await };
|
||||||
} else {
|
self.save().await?;
|
||||||
d.install().await?;
|
r?;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
self.save().await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn print(&self) -> Result<()> {
|
pub(crate) fn print(&self) -> Result<()> {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue