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.
This commit is contained in:
7
Cargo.lock
generated
7
Cargo.lock
generated
@@ -300,6 +300,12 @@ version = "0.4.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "humansize"
|
name = "humansize"
|
||||||
version = "2.1.3"
|
version = "2.1.3"
|
||||||
@@ -923,6 +929,7 @@ dependencies = [
|
|||||||
"argparse",
|
"argparse",
|
||||||
"blake2",
|
"blake2",
|
||||||
"file-mode",
|
"file-mode",
|
||||||
|
"hex",
|
||||||
"pwd-grp",
|
"pwd-grp",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ edition = "2021"
|
|||||||
argparse = "0.2.2"
|
argparse = "0.2.2"
|
||||||
blake2 = "0.10.6"
|
blake2 = "0.10.6"
|
||||||
file-mode = { version = "0.1.2", features = ["serde"] }
|
file-mode = { version = "0.1.2", features = ["serde"] }
|
||||||
|
hex = "0.4.3"
|
||||||
pwd-grp = "0.1.1"
|
pwd-grp = "0.1.1"
|
||||||
serde = { version = "1.0.195", features = ["derive"] }
|
serde = { version = "1.0.195", features = ["derive"] }
|
||||||
serde_yaml = "0.9.30"
|
serde_yaml = "0.9.30"
|
||||||
|
|||||||
43
src/main.rs
43
src/main.rs
@@ -12,7 +12,7 @@ use serde::de::DeserializeOwned;
|
|||||||
use serde_yaml::Value;
|
use serde_yaml::Value;
|
||||||
use shlex::Shlex;
|
use shlex::Shlex;
|
||||||
use tera::{Context, Tera};
|
use tera::{Context, Tera};
|
||||||
use tracing::{debug, error, info, warn};
|
use tracing::{debug, error, info, trace, warn};
|
||||||
|
|
||||||
use model::Instructions;
|
use model::Instructions;
|
||||||
|
|
||||||
@@ -161,13 +161,18 @@ fn process_instructions(
|
|||||||
};
|
};
|
||||||
let mut dest = PathBuf::from(destdir.as_ref());
|
let mut dest = PathBuf::from(destdir.as_ref());
|
||||||
dest.push(i.dest.strip_prefix("/").unwrap_or(i.dest.as_path()));
|
dest.push(i.dest.strip_prefix("/").unwrap_or(i.dest.as_path()));
|
||||||
let orig_cksm = checksum(&dest).ok();
|
let changed = match write_file(&dest, out.as_bytes()) {
|
||||||
if let Err(e) = write_file(&dest, out.as_bytes()) {
|
Ok(c) => c,
|
||||||
error!("Failed to write output file {}: {}", dest.display(), e);
|
Err(e) => {
|
||||||
continue;
|
error!(
|
||||||
}
|
"Failed to write output file {}: {}",
|
||||||
let new_cksm = checksum(&dest).ok();
|
dest.display(),
|
||||||
if orig_cksm != new_cksm {
|
e
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if changed {
|
||||||
info!("File {} was changed", dest.display());
|
info!("File {} was changed", dest.display());
|
||||||
if let Some(hooks) = i.hooks {
|
if let Some(hooks) = i.hooks {
|
||||||
if let Some(changed) = hooks.changed {
|
if let Some(changed) = hooks.changed {
|
||||||
@@ -219,19 +224,37 @@ fn process_instructions(
|
|||||||
fn write_file(
|
fn write_file(
|
||||||
dest: impl AsRef<Path>,
|
dest: impl AsRef<Path>,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Result<(), std::io::Error> {
|
) -> Result<bool, std::io::Error> {
|
||||||
if let Some(p) = dest.as_ref().parent() {
|
if let Some(p) = dest.as_ref().parent() {
|
||||||
if !p.exists() {
|
if !p.exists() {
|
||||||
info!("Creating directory {}", p.display());
|
info!("Creating directory {}", p.display());
|
||||||
std::fs::create_dir_all(p)?;
|
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());
|
debug!("Writing output: {}", dest.as_ref().display());
|
||||||
let mut f = std::fs::File::create(&dest)?;
|
let mut f = std::fs::File::create(&dest)?;
|
||||||
f.write_all(data)?;
|
f.write_all(data)?;
|
||||||
let size = f.stream_position()?;
|
let size = f.stream_position()?;
|
||||||
debug!("Wrote output: {} ({} bytes)", dest.as_ref().display(), size);
|
debug!("Wrote output: {} ({} bytes)", dest.as_ref().display(), size);
|
||||||
Ok(())
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chown(
|
fn chown(
|
||||||
|
|||||||
Reference in New Issue
Block a user