From 1099fa40c79316a040510b432e0f3d9cd5309e0b Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Thu, 18 Jan 2024 19:46:25 -0600 Subject: [PATCH] write_file: Do not overwrite with same content The `write_file` function will no longer overwrite existing files if the content has not changed. This will ensure file metadata timestamps are accurate, and reduce unnecessary filesystem activity. --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + src/main.rs | 43 +++++++++++++++++++++++++++++++++---------- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9188545..70d2046 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -300,6 +300,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "humansize" version = "2.1.3" @@ -923,6 +929,7 @@ dependencies = [ "argparse", "blake2", "file-mode", + "hex", "pwd-grp", "serde", "serde_yaml", diff --git a/Cargo.toml b/Cargo.toml index b5a2c1c..0621df9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" argparse = "0.2.2" blake2 = "0.10.6" file-mode = { version = "0.1.2", features = ["serde"] } +hex = "0.4.3" pwd-grp = "0.1.1" serde = { version = "1.0.195", features = ["derive"] } serde_yaml = "0.9.30" diff --git a/src/main.rs b/src/main.rs index cf49f57..cfbab2c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ use serde::de::DeserializeOwned; use serde_yaml::Value; use shlex::Shlex; use tera::{Context, Tera}; -use tracing::{debug, error, info, warn}; +use tracing::{debug, error, info, trace, warn}; use model::Instructions; @@ -161,13 +161,18 @@ fn process_instructions( }; let mut dest = PathBuf::from(destdir.as_ref()); dest.push(i.dest.strip_prefix("/").unwrap_or(i.dest.as_path())); - let orig_cksm = checksum(&dest).ok(); - if let Err(e) = write_file(&dest, out.as_bytes()) { - error!("Failed to write output file {}: {}", dest.display(), e); - continue; - } - let new_cksm = checksum(&dest).ok(); - if orig_cksm != new_cksm { + let changed = match write_file(&dest, out.as_bytes()) { + Ok(c) => c, + Err(e) => { + error!( + "Failed to write output file {}: {}", + dest.display(), + e + ); + continue; + } + }; + if changed { info!("File {} was changed", dest.display()); if let Some(hooks) = i.hooks { if let Some(changed) = hooks.changed { @@ -219,19 +224,37 @@ fn process_instructions( fn write_file( dest: impl AsRef, data: &[u8], -) -> Result<(), std::io::Error> { +) -> Result { if let Some(p) = dest.as_ref().parent() { if !p.exists() { info!("Creating directory {}", p.display()); std::fs::create_dir_all(p)?; } } + if let Ok(orig_cksm) = checksum(&dest) { + trace!( + "Original checksum: {}: {}", + dest.as_ref().display(), + hex::encode(&orig_cksm) + ); + let mut blake = Blake2b512::new(); + blake.update(data); + let new_cksm = blake.finalize().to_vec(); + trace!( + "New checksum: {}: {}", + dest.as_ref().display(), + hex::encode(&new_cksm) + ); + if orig_cksm == new_cksm { + return Ok(false); + } + } debug!("Writing output: {}", dest.as_ref().display()); let mut f = std::fs::File::create(&dest)?; f.write_all(data)?; let size = f.stream_position()?; debug!("Wrote output: {} ({} bytes)", dest.as_ref().display(), size); - Ok(()) + Ok(true) } fn chown(