Skip to content

Commit d2cc73c

Browse files
authored
fix: ensure state synchronization even when the package update fails midway (#2613)
1 parent af92b92 commit d2cc73c

File tree

7 files changed

+97
-92
lines changed

7 files changed

+97
-92
lines changed

yazi-cli/src/package/add.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ impl Dependency {
88
self.header("Upgrading package `{name}`")?;
99

1010
let path = self.local();
11-
if !must_exists(&path).await {
12-
Git::clone(&self.remote(), &path).await?;
13-
} else {
11+
if must_exists(&path).await {
1412
Git::pull(&path).await?;
13+
} else {
14+
Git::clone(&self.remote(), &path).await?;
1515
};
1616

17-
self.rev = Git::hash(&path).await?;
17+
self.rev = Git::revision(&path).await?;
1818
self.deploy().await
1919
}
2020
}

yazi-cli/src/package/delete.rs

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use anyhow::{Context, Result, bail};
1+
use anyhow::{Context, Result};
22
use tokio::fs;
33
use yazi_fs::{maybe_exists, ok_or_not_found, remove_dir_clean, remove_sealed};
44
use yazi_macro::outln;
@@ -14,36 +14,9 @@ impl Dependency {
1414
return Ok(outln!("Not found, skipping")?);
1515
}
1616

17-
if self.hash != self.hash().await? {
18-
bail!(
19-
"You have modified the contents of the `{}` {}. For safety, the operation has been aborted.
20-
Please manually delete it from: {}",
21-
self.name,
22-
if self.is_flavor { "flavor" } else { "plugin" },
23-
dir.display()
24-
);
25-
}
26-
27-
let files = if self.is_flavor {
28-
&["flavor.toml", "tmtheme.xml", "README.md", "preview.png", "LICENSE", "LICENSE-tmtheme"][..]
29-
} else {
30-
&["main.lua", "README.md", "LICENSE"][..]
31-
};
32-
for p in files.iter().map(|&f| dir.join(f)) {
33-
ok_or_not_found(remove_sealed(&p).await)
34-
.with_context(|| format!("failed to delete `{}`", p.display()))?;
35-
}
36-
17+
self.hash_check().await?;
3718
self.delete_assets().await?;
38-
if ok_or_not_found(fs::remove_dir(&dir).await).is_ok() {
39-
outln!("Done!")?;
40-
} else {
41-
outln!(
42-
"Done!
43-
For safety, user data has been preserved, please manually delete them within: {}",
44-
dir.display()
45-
)?;
46-
}
19+
self.delete_sources().await?;
4720

4821
Ok(())
4922
}
@@ -65,4 +38,29 @@ For safety, user data has been preserved, please manually delete them within: {}
6538
remove_dir_clean(&assets).await;
6639
Ok(())
6740
}
41+
42+
pub(super) async fn delete_sources(&self) -> Result<()> {
43+
let dir = self.target();
44+
let files = if self.is_flavor {
45+
&["flavor.toml", "tmtheme.xml", "README.md", "preview.png", "LICENSE", "LICENSE-tmtheme"][..]
46+
} else {
47+
&["main.lua", "README.md", "LICENSE"][..]
48+
};
49+
50+
for p in files.iter().map(|&f| dir.join(f)) {
51+
ok_or_not_found(remove_sealed(&p).await)
52+
.with_context(|| format!("failed to delete `{}`", p.display()))?;
53+
}
54+
55+
if ok_or_not_found(fs::remove_dir(&dir).await).is_ok() {
56+
outln!("Done!")?;
57+
} else {
58+
outln!(
59+
"Done!
60+
For safety, user data has been preserved, please manually delete them within: {}",
61+
dir.display()
62+
)?;
63+
}
64+
Ok(())
65+
}
6866
}

yazi-cli/src/package/deploy.rs

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::path::{Path, PathBuf};
22

3-
use anyhow::{Context, Result, bail};
3+
use anyhow::{Context, Result};
44
use tokio::fs;
55
use yazi_fs::{copy_and_seal, maybe_exists, remove_dir_clean};
66
use yazi_macro::outln;
@@ -15,44 +15,27 @@ impl Dependency {
1515
self.is_flavor = maybe_exists(&from.join("flavor.toml")).await;
1616

1717
let to = self.target();
18-
if maybe_exists(&to).await && self.hash != self.hash().await? {
19-
bail!(
20-
"You have modified the contents of the `{}` {}. For safety, the operation has been aborted.
21-
Please manually delete it from `{}` and re-run the command.",
22-
self.name,
23-
if self.is_flavor { "flavor" } else { "plugin" },
24-
to.display()
25-
);
18+
let exists = maybe_exists(&to).await;
19+
if exists {
20+
self.hash_check().await?;
2621
}
2722

2823
fs::create_dir_all(&to).await?;
29-
if let Err(e) = Self::deploy_sources(&from, &to, self.is_flavor).await {
30-
remove_dir_clean(&to).await;
31-
return Err(e);
32-
}
33-
3424
self.delete_assets().await?;
35-
Self::deploy_assets(from.join("assets"), to.join("assets")).await?;
36-
37-
self.hash = self.hash().await?;
38-
outln!("Done!")?;
3925

40-
Ok(())
41-
}
26+
let res1 = Self::deploy_assets(from.join("assets"), to.join("assets")).await;
27+
let res2 = Self::deploy_sources(&from, &to, self.is_flavor).await;
28+
if !exists && (res2.is_err() || res1.is_err()) {
29+
self.delete_assets().await?;
30+
self.delete_sources().await?;
31+
}
4232

43-
async fn deploy_sources(from: &Path, to: &Path, is_flavor: bool) -> Result<()> {
44-
let files = if is_flavor {
45-
&["flavor.toml", "tmtheme.xml", "README.md", "preview.png", "LICENSE", "LICENSE-tmtheme"][..]
46-
} else {
47-
&["main.lua", "README.md", "LICENSE"][..]
48-
};
33+
remove_dir_clean(&to).await;
34+
self.hash = self.hash().await?;
35+
res2?;
36+
res1?;
4937

50-
for file in files {
51-
let (from, to) = (from.join(file), to.join(file));
52-
copy_and_seal(&from, &to)
53-
.await
54-
.with_context(|| format!("failed to copy `{}` to `{}`", from.display(), to.display()))?;
55-
}
38+
outln!("Done!")?;
5639
Ok(())
5740
}
5841

@@ -72,4 +55,20 @@ Please manually delete it from `{}` and re-run the command.",
7255
}
7356
Ok(())
7457
}
58+
59+
async fn deploy_sources(from: &Path, to: &Path, is_flavor: bool) -> Result<()> {
60+
let files = if is_flavor {
61+
&["flavor.toml", "tmtheme.xml", "README.md", "preview.png", "LICENSE", "LICENSE-tmtheme"][..]
62+
} else {
63+
&["main.lua", "README.md", "LICENSE"][..]
64+
};
65+
66+
for file in files {
67+
let (from, to) = (from.join(file), to.join(file));
68+
copy_and_seal(&from, &to)
69+
.await
70+
.with_context(|| format!("failed to copy `{}` to `{}`", from.display(), to.display()))?;
71+
}
72+
Ok(())
73+
}
7574
}

yazi-cli/src/package/git.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ impl Git {
2525
Ok(())
2626
}
2727

28-
pub(super) async fn hash(path: &Path) -> Result<String> {
28+
pub(super) async fn revision(path: &Path) -> Result<String> {
2929
let output = Command::new("git")
3030
.args(["rev-parse", "--short", "HEAD"])
3131
.current_dir(path)

yazi-cli/src/package/hash.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,17 @@ impl Dependency {
5252

5353
Ok(format!("{:x}", h.finish_128()))
5454
}
55+
56+
pub(super) async fn hash_check(&self) -> Result<()> {
57+
if self.hash != self.hash().await? {
58+
bail!(
59+
"You have modified the contents of the `{}` {}. For safety, the operation has been aborted.
60+
Please manually delete it from `{}` and re-run the command.",
61+
self.name,
62+
if self.is_flavor { "flavor" } else { "plugin" },
63+
self.target().display()
64+
);
65+
}
66+
Ok(())
67+
}
5568
}

yazi-cli/src/package/install.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ impl Dependency {
1515
};
1616

1717
if self.rev.is_empty() {
18-
self.rev = Git::hash(&path).await?;
18+
self.rev = Git::revision(&path).await?;
1919
} else {
2020
Git::checkout(&path, self.rev.trim_start_matches('=')).await?;
2121
}

yazi-cli/src/package/package.rs

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,41 +25,36 @@ impl Package {
2525

2626
pub(crate) async fn add_many(&mut self, uses: &[String]) -> Result<()> {
2727
for u in uses {
28-
if let Err(e) = self.add(u).await {
29-
self.save().await?;
30-
return Err(e);
31-
}
28+
let r = self.add(u).await;
29+
self.save().await?;
30+
r?;
3231
}
33-
self.save().await
32+
Ok(())
3433
}
3534

3635
pub(crate) async fn delete_many(&mut self, uses: &[String]) -> Result<()> {
3736
for u in uses {
38-
if let Err(e) = self.delete(u).await {
39-
self.save().await?;
40-
return Err(e);
41-
}
37+
let r = self.delete(u).await;
38+
self.save().await?;
39+
r?;
4240
}
43-
self.save().await
41+
Ok(())
4442
}
4543

4644
pub(crate) async fn install(&mut self, upgrade: bool) -> Result<()> {
47-
for d in &mut self.plugins {
48-
if upgrade {
49-
d.upgrade().await?;
50-
} else {
51-
d.install().await?;
52-
}
45+
for i in 0..self.plugins.len() {
46+
let r =
47+
if upgrade { self.plugins[i].upgrade().await } else { self.plugins[i].install().await };
48+
self.save().await?;
49+
r?;
5350
}
54-
for d in &mut self.flavors {
55-
if upgrade {
56-
d.upgrade().await?;
57-
} else {
58-
d.install().await?;
59-
}
51+
for i in 0..self.flavors.len() {
52+
let r =
53+
if upgrade { self.flavors[i].upgrade().await } else { self.flavors[i].install().await };
54+
self.save().await?;
55+
r?;
6056
}
61-
62-
self.save().await
57+
Ok(())
6358
}
6459

6560
pub(crate) fn print(&self) -> Result<()> {

0 commit comments

Comments
 (0)