Skip to content

Commit d0d7d92

Browse files
committed
Add a guard struct that checks whether a file still has the same contents when the guard is dropped
1 parent fe06474 commit d0d7d92

File tree

1 file changed

+43
-1
lines changed

1 file changed

+43
-1
lines changed

collector/src/utils/fs.rs

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use anyhow::Context;
2+
use std::collections::hash_map::DefaultHasher;
23
use std::ffi::OsStr;
34
use std::fs;
4-
use std::path::{Component, Path};
5+
use std::hash::{Hash, Hasher};
6+
use std::path::{Component, Path, PathBuf};
57
use std::process::Command;
68

79
#[cfg(windows)]
@@ -142,6 +144,46 @@ pub fn robocopy(
142144
Ok(())
143145
}
144146

147+
/// Loads contents of a file and hashes it when it is created.
148+
/// It then asserts that when it is dropped, the file still has the same contents.
149+
#[must_use = "EnsureImmutableFile acts like a guard, consider keeping it alive until something can happen with the file"]
150+
pub struct EnsureImmutableFile {
151+
path: PathBuf,
152+
hash: u64,
153+
name: String,
154+
}
155+
156+
impl EnsureImmutableFile {
157+
pub fn new(path: &Path, name: String) -> anyhow::Result<Self> {
158+
let hash = Self::hash(path)?;
159+
Ok(Self {
160+
path: path.to_path_buf(),
161+
hash,
162+
name,
163+
})
164+
}
165+
166+
fn hash(path: &Path) -> anyhow::Result<u64> {
167+
let contents = fs::read(path)?;
168+
let mut hasher = DefaultHasher::new();
169+
contents.hash(&mut hasher);
170+
Ok(hasher.finish())
171+
}
172+
}
173+
174+
impl Drop for EnsureImmutableFile {
175+
fn drop(&mut self) {
176+
let hash = Self::hash(&self.path).expect("Cannot hash file");
177+
assert_eq!(
178+
self.hash,
179+
hash,
180+
"{} ({}) has changed during a build",
181+
self.path.display(),
182+
self.name
183+
);
184+
}
185+
}
186+
145187
#[cfg(test)]
146188
mod tests {
147189
use super::get_file_count_and_size;

0 commit comments

Comments
 (0)