Skip to content

Commit 4653f6f

Browse files
committed
feat: skip update if target file already exists with correct checksum
1 parent 3a03297 commit 4653f6f

4 files changed

Lines changed: 117 additions & 17 deletions

File tree

Cargo.lock

Lines changed: 69 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ edition = "2024"
55

66
[dependencies]
77
clap = { version = "4.6.0", features = ["derive"] }
8+
hex = "0.4.3"
89
serde = { version = "1.0.228", features = ["derive"] }
910
serde_json = "1.0.149"
11+
sha1 = "0.10.6"
1012
thiserror = "2.0.18"
1113
ureq = "3.3.0"
1214
zsync-rs = { git = "https://github.com/QaidVoid/zsync-rs.git", version = "0.1.0" }

src/main.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ fn run(cli: Cli) -> Result<(), Error> {
6565
let new_path = updater.perform_update()?;
6666
println!("Updated AppImage: {}", new_path.display());
6767
} else {
68-
println!("No update available.");
68+
let output_path = updater.output_path()?;
69+
println!("Already up to date: {}", output_path.display());
6970
}
7071
}
7172
Commands::Check { path } => {

src/updater.rs

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,35 @@ impl Updater {
7373
Ok(self.output_dir.join(filename))
7474
}
7575

76+
fn verify_existing_file(&self, path: &Path, expected_sha1: &str) -> Result<bool> {
77+
use sha1::{Digest, Sha1};
78+
79+
let mut file = fs::File::open(path)?;
80+
let mut hasher = Sha1::new();
81+
std::io::copy(&mut file, &mut hasher)?;
82+
let hash = hasher.finalize();
83+
let actual_sha1 = hex::encode(hash);
84+
85+
Ok(actual_sha1.eq_ignore_ascii_case(expected_sha1))
86+
}
87+
7688
pub fn check_for_update(&self) -> Result<bool> {
7789
let (control, _zsync_url) = self.fetch_control_file()?;
78-
7990
let output_path = self.resolve_output_path(&control)?;
80-
if output_path.exists() && !self.overwrite {
81-
return Err(Error::AppImage(format!(
82-
"Output file already exists: {}",
83-
output_path.display()
84-
)));
91+
92+
if output_path.exists() {
93+
if let Some(ref expected_sha1) = control.sha1
94+
&& self.verify_existing_file(&output_path, expected_sha1)?
95+
{
96+
return Ok(false);
97+
}
98+
99+
if !self.overwrite {
100+
return Err(Error::AppImage(format!(
101+
"Output file already exists: {}",
102+
output_path.display()
103+
)));
104+
}
85105
}
86106

87107
Ok(true)
@@ -91,11 +111,19 @@ impl Updater {
91111
let (control, zsync_url) = self.fetch_control_file()?;
92112
let output_path = self.resolve_output_path(&control)?;
93113

94-
if output_path.exists() && !self.overwrite {
95-
return Err(Error::AppImage(format!(
96-
"Output file already exists: {}",
97-
output_path.display()
98-
)));
114+
if output_path.exists() {
115+
if let Some(ref expected_sha1) = control.sha1
116+
&& self.verify_existing_file(&output_path, expected_sha1)?
117+
{
118+
return Ok(output_path);
119+
}
120+
121+
if !self.overwrite {
122+
return Err(Error::AppImage(format!(
123+
"Output file already exists: {}",
124+
output_path.display()
125+
)));
126+
}
99127
}
100128

101129
let original_perms = fs::metadata(self.appimage.path())
@@ -130,6 +158,11 @@ impl Updater {
130158
Ok(output_path)
131159
}
132160

161+
pub fn output_path(&self) -> Result<PathBuf> {
162+
let (control, _zsync_url) = self.fetch_control_file()?;
163+
self.resolve_output_path(&control)
164+
}
165+
133166
pub fn progress(&self) -> Option<(u64, u64)> {
134167
None
135168
}

0 commit comments

Comments
 (0)