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
pub async fn diff(config: &fpm::Config, files: Option<Vec<String>>, all: bool) -> fpm::Result<()> {
let snapshots = fpm::snapshot::get_latest_snapshots(&config.root).await?;
let all = all || files.is_some();
let documents = if let Some(ref files) = files {
let files = files
.to_vec()
.into_iter()
.map(|x| config.root.join(x))
.collect::<Vec<camino::Utf8PathBuf>>();
fpm::paths_to_files(files, config.root.as_path()).await?
} else {
fpm::get_documents(config).await?
};
for doc in documents {
if let Some(diff) = get_diffy(&doc, &snapshots).await? {
println!("diff: {}", doc.get_id());
println!("{}", diff);
}
if all {
get_track_diff(&doc, &snapshots, config.root.as_str()).await?;
}
}
Ok(())
}
async fn get_diffy(
doc: &fpm::File,
snapshots: &std::collections::BTreeMap<String, u128>,
) -> fpm::Result<Option<String>> {
if let Some(timestamp) = snapshots.get(&doc.get_id()) {
let path = fpm::utils::history_path(&doc.get_id(), &doc.get_base_path(), timestamp);
let content = tokio::fs::read_to_string(&doc.get_full_path()).await?;
let existing_doc = tokio::fs::read_to_string(&path).await?;
if content.eq(&existing_doc) {
return Ok(None);
}
let patch = diffy::create_patch(&existing_doc, &content);
let diff = diffy::PatchFormatter::new()
.with_color()
.fmt_patch(&patch)
.to_string();
return Ok(Some(diff));
}
Ok(None)
}
async fn get_track_diff(
doc: &fpm::File,
snapshots: &std::collections::BTreeMap<String, u128>,
base_path: &str,
) -> fpm::Result<()> {
let path = fpm::utils::track_path(&doc.get_id(), &doc.get_base_path());
if std::fs::metadata(&path).is_err() {
return Ok(());
}
let tracks = fpm::tracker::get_tracks(base_path, &path)?;
for track in tracks.values() {
if let Some(timestamp) = snapshots.get(&track.filename) {
if track.other_timestamp.is_none() {
continue;
}
let now_path =
fpm::utils::history_path(&track.filename, &doc.get_base_path(), timestamp);
let then_path = fpm::utils::history_path(
&track.filename,
&doc.get_base_path(),
track.other_timestamp.as_ref().unwrap(),
);
let now_doc = tokio::fs::read_to_string(&now_path).await?;
let then_doc = tokio::fs::read_to_string(&then_path).await?;
if now_doc.eq(&then_doc) {
continue;
}
let patch = diffy::create_patch(&then_doc, &now_doc);
let diff = diffy::PatchFormatter::new()
.with_color()
.fmt_patch(&patch)
.to_string();
println!(
"diff {} -> {}: {}",
doc.get_id(),
then_path
.to_string()
.replace(&format!("{}/.history/", doc.get_base_path()), ""),
now_path
.to_string()
.replace(&format!("{}/.history/", doc.get_base_path()), ""),
);
println!("{}", diff);
}
}
Ok(())
}