1use md5::{Digest, Md5};
2use std::collections::HashMap;
3use std::env;
4use std::fs::{self, File};
5use std::io;
6use std::path::{self, Path, PathBuf};
7
8#[derive(Debug)]
9pub struct Config {
10 pub dir: String,
11 pub output_file: String,
12}
13
14impl Config {
15 pub fn new(mut args: env::Args) -> Result<Config, &'static str> {
16 args.next();
17
18 let dir = match args.next() {
19 Some(arg) => arg,
20 None => return Err("no dir"),
21 };
22
23 let output_file = match args.next() {
24 Some(arg) => arg,
25 None => return Err("no output_file"),
26 };
27
28 Ok(Config { dir, output_file })
29 }
30}
31
32#[derive(Debug)]
33pub struct HashInfo {
34 pub path: PathBuf,
35 pub hash: String,
36}
37
38pub fn dir_files(dir: &Path) -> io::Result<HashMap<String, HashInfo>> {
39 let mut files: HashMap<String, HashInfo> = HashMap::new();
40 visit_dirs(dir, "", &mut |key, path: PathBuf| {
41 files.insert(
42 key,
43 HashInfo {
44 path,
45 hash: String::new(),
46 },
47 );
48 })?;
49 Ok(files)
50}
51
52fn visit_dirs(dir: &Path, prefix: &str, cb: &mut dyn FnMut(String, PathBuf)) -> io::Result<()> {
53 if dir.is_dir() {
54 for entry in fs::read_dir(dir)? {
55 let entry = entry?;
56 let path = entry.path();
57 let file_name = entry.file_name().into_string().unwrap();
58
59 if path.is_dir() {
60 let prefix = prefix.to_string() + &file_name + path::MAIN_SEPARATOR_STR;
61 visit_dirs(&path, &prefix, cb)?;
62 } else {
63 let key = format!("{}{}", prefix, &file_name);
64 cb(key, path);
65 }
66 }
67 }
68 Ok(())
69}
70
71pub fn md5_file<P>(path: P) -> io::Result<String>
72where
73 P: AsRef<Path>,
74{
75 let mut hasher = Md5::new();
76
77 let mut file: fs::File = File::open(path)?;
78 io::copy(&mut file, &mut hasher)?;
79 let hash = hasher.finalize();
80 Ok(hex::encode(hash))
81}
82
83pub fn sorted_hash_result(files: &HashMap<String, HashInfo>) -> String {
84 let mut keys: Vec<_> = files.keys().collect();
85 keys.sort();
86 let mut text = String::new();
87 for key in keys.into_iter() {
88 let hash = &files[key].hash;
89 text += &format!("{} {}\n", hash, key);
90 }
91 text
92}