61 lines
1.7 KiB
Rust
61 lines
1.7 KiB
Rust
use sha2::{Digest, Sha256};
|
|
use std::{
|
|
fs::File,
|
|
io::{self, Read, Write},
|
|
path::Path,
|
|
};
|
|
use walkdir::WalkDir;
|
|
|
|
pub fn hash_reader(name: &str, reader: &mut dyn Read) -> io::Result<String> {
|
|
let mut hasher = Sha256::new();
|
|
io::copy(reader, &mut hasher)?;
|
|
Ok(format!("{} {}\n", hex::encode(hasher.finalize()), name))
|
|
}
|
|
|
|
fn hash_file(fname: &Path, name: &Path) -> io::Result<String> {
|
|
let mut fin = File::open(name)?;
|
|
hash_reader(fname.as_os_str().to_str().unwrap(), &mut fin)
|
|
}
|
|
|
|
pub fn hash_dir(name: &str) -> io::Result<String> {
|
|
let mut result = String::new();
|
|
|
|
for entry in WalkDir::new(name)
|
|
.into_iter()
|
|
.filter(Result::is_ok)
|
|
.map(Result::unwrap)
|
|
.filter(|dir_entry| !dir_entry.file_type().is_dir())
|
|
.map(|de| de.into_path())
|
|
.map(|de| hash_file(&de.strip_prefix(name).unwrap(), &de))
|
|
{
|
|
result.push_str(&entry?);
|
|
}
|
|
|
|
let mut hasher = Sha256::new();
|
|
hasher.write_all(&result.as_bytes())?;
|
|
Ok(format!("h1:{}", base64::encode(hasher.finalize())))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use std::process::Command;
|
|
|
|
#[test]
|
|
fn hash_dir() {
|
|
let hash = super::hash_dir("./testdata").unwrap();
|
|
assert_eq!("h1:nJxVO77692drULxxVJvOrMJE8fl8vG1NLjoDDv9e7+E=", &hash);
|
|
}
|
|
|
|
#[test]
|
|
fn test_compare_go() {
|
|
let rust_hash = super::hash_dir("./testdata").unwrap();
|
|
let go_output = Command::new("go")
|
|
.arg("run")
|
|
.arg("./go_cmp")
|
|
.output()
|
|
.expect("go to run");
|
|
let go_hash: String = String::from_utf8(go_output.stdout).expect("go output to be utf-8");
|
|
assert_eq!(go_hash, rust_hash);
|
|
}
|
|
}
|