rebterlai/crates/dirhash/src/lib.rs

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);
}
}