1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use self::super::super::util::vec_merge;
use std::collections::BTreeMap;
use std::iter;
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum CompareResult {
FileAdded(String),
FileRemoved(String),
FileIgnored(String),
}
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum CompareFileResult {
FileMatches(String),
FileDiffers {
file: String,
was_hash: String,
new_hash: String,
},
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum CompareError {
HashLengthDiffers {
previous_len: usize,
current_len: usize,
},
}
pub fn compare_hashes(out_file: &String, mut current_hashes: BTreeMap<String, String>, mut loaded_hashes: BTreeMap<String, String>)
-> Result<(Vec<CompareResult>, Vec<CompareFileResult>), CompareError> {
let current_hashes_value_len = current_hashes.iter().next().unwrap().1.len();
let loaded_hashes_value_len = loaded_hashes.iter().next().unwrap().1.len();
if current_hashes_value_len != loaded_hashes_value_len {
return Err(CompareError::HashLengthDiffers {
previous_len: loaded_hashes_value_len,
current_len: current_hashes_value_len,
});
}
let placeholder_value = iter::repeat("-").take(current_hashes_value_len).collect::<String>();
let mut file_compare_results = Vec::new();
current_hashes.remove(out_file);
loaded_hashes.remove(out_file);
let remove_results = process_ignores(|key, _, other| !other.contains_key(key),
CompareResult::FileAdded,
CompareResult::FileRemoved,
&mut current_hashes,
&mut loaded_hashes);
let ignore_results = process_ignores(|_, value, _| *value == placeholder_value,
CompareResult::FileIgnored,
CompareResult::FileIgnored,
&mut current_hashes,
&mut loaded_hashes);
assert_eq!(current_hashes.len(), loaded_hashes.len());
if !current_hashes.is_empty() {
for (key, loaded_value) in loaded_hashes {
let ref current_value = current_hashes[&key];
if *current_value == loaded_value {
file_compare_results.push(CompareFileResult::FileMatches(key));
} else {
file_compare_results.push(CompareFileResult::FileDiffers {
file: key,
was_hash: loaded_value,
new_hash: current_value.clone(),
});
}
}
}
Ok((vec_merge(remove_results, ignore_results), file_compare_results))
}
fn process_ignores<F, Rc, Rl>(f: F, cres: Rc, lres: Rl, ch: &mut BTreeMap<String, String>, lh: &mut BTreeMap<String, String>) -> Vec<CompareResult>
where F: Fn(&String, &String, &BTreeMap<String, String>) -> bool,
Rc: Fn(String) -> CompareResult,
Rl: Fn(String) -> CompareResult
{
let mut results = Vec::new();
let mut keys_to_remove = Vec::new();
process_ignores_iter(&f, &cres, ch, lh, &mut keys_to_remove, &mut results);
process_ignores_iter(&f, &lres, lh, ch, &mut keys_to_remove, &mut results);
for key in keys_to_remove {
ch.remove(&key);
lh.remove(&key);
}
results
}
fn process_ignores_iter<F, R>(f: &F, res: &R, curr: &BTreeMap<String, String>, other: &BTreeMap<String, String>, keys_to_remove: &mut Vec<String>,
results: &mut Vec<CompareResult>)
where F: Fn(&String, &String, &BTreeMap<String, String>) -> bool,
R: Fn(String) -> CompareResult
{
for (key, value) in curr {
if f(key, value, other) {
results.push(res(key.clone()));
keys_to_remove.push(key.clone());
}
}
}