ok/jj
1
0
Fork 0
forked from mirrors/jj

working_copy: extract a function for updating the file state and tree if dirty

This commit is contained in:
Martin von Zweigbergk 2021-11-03 08:48:30 -07:00 committed by Martin von Zweigbergk
parent 730c442462
commit 7c12014513

View file

@ -41,6 +41,7 @@ use crate::matchers::EverythingMatcher;
use crate::repo_path::{RepoPath, RepoPathComponent, RepoPathJoin}; use crate::repo_path::{RepoPath, RepoPathComponent, RepoPathJoin};
use crate::store::Store; use crate::store::Store;
use crate::tree::Diff; use crate::tree::Diff;
use crate::tree_builder::TreeBuilder;
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub enum FileType { pub enum FileType {
@ -298,8 +299,7 @@ impl TreeState {
let mut work = vec![(RepoPath::root(), self.working_copy_path.clone(), git_ignore)]; let mut work = vec![(RepoPath::root(), self.working_copy_path.clone(), git_ignore)];
let mut tree_builder = self.store.tree_builder(self.tree_id.clone()); let mut tree_builder = self.store.tree_builder(self.tree_id.clone());
let mut deleted_files: HashSet<&RepoPath> = self.file_states.keys().collect(); let mut deleted_files: HashSet<_> = self.file_states.keys().cloned().collect();
let mut modified_files = BTreeMap::new();
while !work.is_empty() { while !work.is_empty() {
let (dir, disk_dir, git_ignore) = work.pop().unwrap(); let (dir, disk_dir, git_ignore) = work.pop().unwrap();
let git_ignore = TreeState::try_chain_gitignore( let git_ignore = TreeState::try_chain_gitignore(
@ -335,74 +335,79 @@ impl TreeState {
} }
work.push((sub_path, entry.path(), git_ignore.clone())); work.push((sub_path, entry.path(), git_ignore.clone()));
} else { } else {
let disk_file = entry.path();
deleted_files.remove(&sub_path); deleted_files.remove(&sub_path);
let current_file_state = self.file_states.get(&sub_path); self.update_file_state(
sub_path,
entry.path(),
git_ignore.as_ref(),
&mut tree_builder,
);
}
}
}
for file in &deleted_files {
self.file_states.remove(file);
tree_builder.remove(file.clone());
}
self.tree_id = tree_builder.write_tree();
self.save();
&self.tree_id
}
fn update_file_state(
&mut self,
repo_path: RepoPath,
disk_path: PathBuf,
git_ignore: &GitIgnoreFile,
tree_builder: &mut TreeBuilder,
) {
let current_file_state = self.file_states.get(&repo_path);
if current_file_state.is_none() if current_file_state.is_none()
&& git_ignore.matches_file(&sub_path.to_internal_file_string()) && git_ignore.matches_file(&repo_path.to_internal_file_string())
{ {
// If it wasn't already tracked and it matches the ignored paths, then // If it wasn't already tracked and it matches the ignored paths, then
// ignore it. // ignore it.
continue; return;
} }
let new_file_state = file_state(&disk_file).unwrap(); let new_file_state = file_state(&disk_path).unwrap();
let clean; let clean;
let executable; let executable;
match current_file_state { match current_file_state {
None => { None => {
// untracked // untracked
clean = false; clean = false;
executable = executable = new_file_state.file_type == FileType::Normal { executable: true };
new_file_state.file_type == FileType::Normal { executable: true };
} }
Some(current_entry) => { Some(current_entry) => {
clean = current_entry == &new_file_state clean = current_entry == &new_file_state && current_entry.mtime < self.read_time;
&& current_entry.mtime < self.read_time;
#[cfg(windows)] #[cfg(windows)]
{ {
// On Windows, we preserve the state we had recorded // On Windows, we preserve the state we had recorded
// when we wrote the file. // when we wrote the file.
executable = executable = current_entry.file_type == FileType::Normal { executable: true }
current_entry.file_type == FileType::Normal { executable: true }
} }
#[cfg(unix)] #[cfg(unix)]
{ {
executable = new_file_state.file_type executable = new_file_state.file_type == FileType::Normal { executable: true }
== FileType::Normal { executable: true }
} }
} }
}; };
if !clean { if !clean {
let file_value = match new_file_state.file_type { let file_value = match new_file_state.file_type {
FileType::Normal { .. } => { FileType::Normal { .. } => {
let id = self.write_file_to_store(&sub_path, &disk_file); let id = self.write_file_to_store(&repo_path, &disk_path);
TreeValue::Normal { id, executable } TreeValue::Normal { id, executable }
} }
FileType::Symlink => { FileType::Symlink => {
let id = self.write_symlink_to_store(&sub_path, &disk_file); let id = self.write_symlink_to_store(&repo_path, &disk_path);
TreeValue::Symlink(id) TreeValue::Symlink(id)
} }
}; };
tree_builder.set(sub_path.clone(), file_value); tree_builder.set(repo_path.clone(), file_value);
modified_files.insert(sub_path, new_file_state); self.file_states.insert(repo_path, new_file_state);
} }
} }
}
}
let deleted_files: Vec<RepoPath> = deleted_files.iter().cloned().cloned().collect();
for file in &deleted_files {
self.file_states.remove(file);
tree_builder.remove(file.clone());
}
for (file, file_state) in modified_files {
self.file_states.insert(file, file_state);
}
self.tree_id = tree_builder.write_tree();
self.save();
&self.tree_id
}
fn write_file( fn write_file(
&self, &self,