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
114
115
116
117
|
use std::time::SystemTime;
use anyhow::{Context, Result};
use crate::{
diff::ContentChange,
files::{FileState, Locations},
filesystem::Fs,
history::{FileChange, FileChangeVariant, FileHistory, RepositoryChange, RepositoryHistory},
};
use super::ActionOptions;
pub fn update(command_options: ActionOptions, fs: &impl Fs) -> Result<()> {
let timestamp = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)?
.as_secs();
let locations = Locations::from(&command_options);
let repository_index_path = locations.get_repository_index_path();
let mut repository_index_file = fs.open_writable_file(&repository_index_path)?;
let mut repository_history = RepositoryHistory::from_file(fs, &mut repository_index_file)?;
let entries = locations
.get_repository_files(fs)
.context("Could not traverse files.")?;
let mut affected_files = Vec::new();
for state in entries {
let changed_file =
get_new_history_for_file(fs, repository_history.cursor, &state, &locations)?;
if let Some((mut history_file, new_file_history)) = changed_file {
new_file_history.write_to_file(fs, &mut history_file)?;
affected_files.push(state.get_working_path(&locations)?);
}
}
if affected_files.len() > 0 {
repository_history.add_change(RepositoryChange {
affected_files,
timestamp,
});
repository_history.cursor += 1;
repository_history.write_to_file(fs, &mut repository_index_file)?;
}
Ok(())
}
fn get_new_history_for_file<FS: Fs>(
fs: &FS,
cursor: usize,
file_state: &FileState,
locations: &Locations,
) -> Result<Option<(FS::File, FileHistory)>> {
match file_state {
FileState::Deleted(deleted) => {
let mut history_file = deleted.load_history_file(fs)?;
let file_history = FileHistory::from_file(fs, &mut history_file)?;
if !file_history.is_file_deleted(cursor) {
let mut new_history = file_history;
new_history.add_change(FileChange {
change_index: cursor + 1,
variant: FileChangeVariant::Deleted,
});
Ok(Some((history_file, new_history)))
} else {
Ok(None)
}
}
FileState::Untracked(untracked) => {
let mut file = untracked.load_file(fs)?;
let file_content = fs.read_from_file(&mut file)?;
let change = FileChange {
change_index: cursor + 1,
variant: FileChangeVariant::Updated(vec![ContentChange::Inserted {
at: 0,
new_content: file_content,
}]),
};
let mut new_history = FileHistory::default();
new_history.add_change(change);
Ok(Some((
untracked.create_history_file(fs, locations)?,
new_history,
)))
}
FileState::Tracked(tracked) => {
let mut history_file = tracked.load_history_file(fs)?;
let mut working_file = tracked.load_working_file(fs)?;
let file_history = FileHistory::from_file(fs, &mut history_file)?;
let new_content = fs.read_from_file(&mut working_file)?;
let old_content = file_history.get_content(cursor);
let changes = ContentChange::diff(&old_content, &new_content);
// TODO: Check if file was changed.
let mut new_history = file_history;
new_history.add_change(FileChange {
change_index: cursor + 1,
variant: FileChangeVariant::Updated(changes),
});
Ok(Some((history_file, new_history)))
}
}
}
|