working_copy: introduce snapshot progress callback

This commit is contained in:
Benjamin Saunders 2023-05-05 16:55:33 -07:00
parent 17be937e3d
commit ccbb34fddb
7 changed files with 37 additions and 24 deletions

View file

@ -482,7 +482,11 @@ impl TreeState {
/// Look for changes to the working copy. If there are any changes, create
/// a new tree from it.
pub fn snapshot(&mut self, base_ignores: Arc<GitIgnoreFile>) -> Result<bool, SnapshotError> {
pub fn snapshot(
&mut self,
base_ignores: Arc<GitIgnoreFile>,
progress: Option<&SnapshotProgress<'_>>,
) -> Result<bool, SnapshotError> {
let sparse_matcher = self.sparse_matcher();
let mut work = vec![(
RepoPath::root(),
@ -535,6 +539,9 @@ impl TreeState {
} else {
deleted_files.remove(&sub_path);
if sparse_matcher.matches(&sub_path) {
if let Some(progress) = progress {
progress(&sub_path);
}
self.update_file_state(
sub_path,
&entry,
@ -1211,9 +1218,13 @@ impl LockedWorkingCopy<'_> {
// The base_ignores are passed in here rather than being set on the TreeState
// because the TreeState may be long-lived if the library is used in a
// long-lived process.
pub fn snapshot(&mut self, base_ignores: Arc<GitIgnoreFile>) -> Result<TreeId, SnapshotError> {
pub fn snapshot(
&mut self,
base_ignores: Arc<GitIgnoreFile>,
progress: Option<&SnapshotProgress<'_>>,
) -> Result<TreeId, SnapshotError> {
let tree_state = self.wc.tree_state_mut();
self.tree_state_dirty |= tree_state.snapshot(base_ignores)?;
self.tree_state_dirty |= tree_state.snapshot(base_ignores, progress)?;
Ok(tree_state.current_tree_id().clone())
}
@ -1278,3 +1289,5 @@ impl Drop for LockedWorkingCopy<'_> {
}
}
}
pub type SnapshotProgress<'a> = dyn Fn(&RepoPath) + 'a;

View file

@ -45,7 +45,7 @@ fn test_root(use_git: bool) {
let wc = test_workspace.workspace.working_copy_mut();
assert_eq!(wc.sparse_patterns(), vec![RepoPath::root()]);
let mut locked_wc = wc.start_mutation();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty()).unwrap();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty(), None).unwrap();
locked_wc.discard();
let wc_commit_id = repo
.view()
@ -209,7 +209,7 @@ fn test_checkout_file_transitions(use_git: bool) {
// Check that the working copy is clean.
let mut locked_wc = wc.start_mutation();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty()).unwrap();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty(), None).unwrap();
locked_wc.discard();
assert_eq!(new_tree_id, right_tree_id);
@ -307,7 +307,7 @@ fn test_reset() {
assert!(ignored_path.to_fs_path(&workspace_root).is_file());
assert!(!wc.file_states().contains_key(&ignored_path));
let mut locked_wc = wc.start_mutation();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty()).unwrap();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty(), None).unwrap();
assert_eq!(new_tree_id, *tree_without_file.id());
locked_wc.discard();
@ -320,7 +320,7 @@ fn test_reset() {
assert!(ignored_path.to_fs_path(&workspace_root).is_file());
assert!(!wc.file_states().contains_key(&ignored_path));
let mut locked_wc = wc.start_mutation();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty()).unwrap();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty(), None).unwrap();
assert_eq!(new_tree_id, *tree_without_file.id());
locked_wc.discard();
@ -332,7 +332,7 @@ fn test_reset() {
assert!(ignored_path.to_fs_path(&workspace_root).is_file());
assert!(wc.file_states().contains_key(&ignored_path));
let mut locked_wc = wc.start_mutation();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty()).unwrap();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty(), None).unwrap();
assert_eq!(new_tree_id, *tree_with_file.id());
locked_wc.discard();
}
@ -408,7 +408,7 @@ fn test_snapshot_racy_timestamps(use_git: bool) {
file.write_all(format!("contents {i}").as_bytes()).unwrap();
}
let mut locked_wc = wc.start_mutation();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty()).unwrap();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty(), None).unwrap();
locked_wc.discard();
assert_ne!(new_tree_id, previous_tree_id);
previous_tree_id = new_tree_id;
@ -440,7 +440,7 @@ fn test_snapshot_special_file() {
// Snapshot the working copy with the socket file
let wc = test_workspace.workspace.working_copy_mut();
let mut locked_wc = wc.start_mutation();
let tree_id = locked_wc.snapshot(GitIgnoreFile::empty()).unwrap();
let tree_id = locked_wc.snapshot(GitIgnoreFile::empty(), None).unwrap();
locked_wc.finish(OperationId::from_hex("abc123"));
let tree = store.get_tree(&RepoPath::root(), &tree_id).unwrap();
// Only the regular files should be in the tree
@ -457,7 +457,7 @@ fn test_snapshot_special_file() {
std::fs::remove_file(&file1_disk_path).unwrap();
UnixListener::bind(&file1_disk_path).unwrap();
let mut locked_wc = wc.start_mutation();
let tree_id = locked_wc.snapshot(GitIgnoreFile::empty()).unwrap();
let tree_id = locked_wc.snapshot(GitIgnoreFile::empty(), None).unwrap();
locked_wc.finish(OperationId::from_hex("abc123"));
let tree = store.get_tree(&RepoPath::root(), &tree_id).unwrap();
// Only the regular file should be in the tree
@ -497,7 +497,7 @@ fn test_gitignores(use_git: bool) {
let wc = test_workspace.workspace.working_copy_mut();
let mut locked_wc = wc.start_mutation();
let new_tree_id1 = locked_wc.snapshot(GitIgnoreFile::empty()).unwrap();
let new_tree_id1 = locked_wc.snapshot(GitIgnoreFile::empty(), None).unwrap();
locked_wc.finish(repo.op_id().clone());
let tree1 = repo
.store()
@ -527,7 +527,7 @@ fn test_gitignores(use_git: bool) {
testutils::write_working_copy_file(&workspace_root, &subdir_ignored_path, "2");
let mut locked_wc = wc.start_mutation();
let new_tree_id2 = locked_wc.snapshot(GitIgnoreFile::empty()).unwrap();
let new_tree_id2 = locked_wc.snapshot(GitIgnoreFile::empty(), None).unwrap();
locked_wc.discard();
let tree2 = repo
.store()
@ -616,7 +616,7 @@ fn test_gitignores_ignored_directory_already_tracked(use_git: bool) {
// Check that the file is still in the tree created by snapshotting the working
// copy (that it didn't get removed because the directory is ignored)
let mut locked_wc = wc.start_mutation();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty()).unwrap();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty(), None).unwrap();
locked_wc.discard();
let new_tree = repo
.store()
@ -646,7 +646,7 @@ fn test_dotgit_ignored(use_git: bool) {
"contents",
);
let mut locked_wc = test_workspace.workspace.working_copy_mut().start_mutation();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty()).unwrap();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty(), None).unwrap();
assert_eq!(new_tree_id, *repo.store().empty_tree_id());
locked_wc.discard();
std::fs::remove_dir_all(&dotgit_path).unwrap();
@ -658,7 +658,7 @@ fn test_dotgit_ignored(use_git: bool) {
"contents",
);
let mut locked_wc = test_workspace.workspace.working_copy_mut().start_mutation();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty()).unwrap();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty(), None).unwrap();
assert_eq!(new_tree_id, *repo.store().empty_tree_id());
locked_wc.discard();
}
@ -712,7 +712,7 @@ fn test_gitsubmodule() {
// Check that the files present in the submodule are not tracked
// when we snapshot
let mut locked_wc = wc.start_mutation();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty()).unwrap();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty(), None).unwrap();
locked_wc.discard();
assert_eq!(new_tree_id, tree_id);

View file

@ -134,7 +134,7 @@ fn test_checkout_parallel(use_git: bool) {
// write_tree() should take the same lock as check_out(), write_tree()
// should never produce a different tree.
let mut locked_wc = workspace.working_copy_mut().start_mutation();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty()).unwrap();
let new_tree_id = locked_wc.snapshot(GitIgnoreFile::empty(), None).unwrap();
locked_wc.discard();
assert!(tree_ids.contains(&new_tree_id));
});

View file

@ -168,7 +168,7 @@ fn test_sparse_commit() {
// Create a tree from the working copy. Only dir1/file1 should be updated in the
// tree.
let mut locked_wc = wc.start_mutation();
let modified_tree_id = locked_wc.snapshot(GitIgnoreFile::empty()).unwrap();
let modified_tree_id = locked_wc.snapshot(GitIgnoreFile::empty(), None).unwrap();
locked_wc.finish(repo.op_id().clone());
let modified_tree = repo
.store()
@ -187,7 +187,7 @@ fn test_sparse_commit() {
// Create a tree from the working copy. Only dir1/file1 and dir2/file1 should be
// updated in the tree.
let mut locked_wc = wc.start_mutation();
let modified_tree_id = locked_wc.snapshot(GitIgnoreFile::empty()).unwrap();
let modified_tree_id = locked_wc.snapshot(GitIgnoreFile::empty(), None).unwrap();
locked_wc.finish(repo.op_id().clone());
let modified_tree = repo
.store()
@ -228,7 +228,7 @@ fn test_sparse_commit_gitignore() {
// Create a tree from the working copy. Only dir1/file2 should be updated in the
// tree because dir1/file1 is ignored.
let mut locked_wc = wc.start_mutation();
let modified_tree_id = locked_wc.snapshot(GitIgnoreFile::empty()).unwrap();
let modified_tree_id = locked_wc.snapshot(GitIgnoreFile::empty(), None).unwrap();
locked_wc.finish(repo.op_id().clone());
let modified_tree = repo
.store()

View file

@ -1000,7 +1000,7 @@ impl WorkspaceCommandHelper {
)));
}
};
let new_tree_id = locked_wc.snapshot(base_ignores)?;
let new_tree_id = locked_wc.snapshot(base_ignores, None)?;
if new_tree_id != *wc_commit.tree_id() {
let mut tx = start_repo_transaction(
&self.repo,

View file

@ -1236,7 +1236,7 @@ fn cmd_untrack(
locked_working_copy.reset(&new_tree)?;
// Commit the working copy again so we can inform the user if paths couldn't be
// untracked because they're not ignored.
let wc_tree_id = locked_working_copy.snapshot(base_ignores)?;
let wc_tree_id = locked_working_copy.snapshot(base_ignores, None)?;
if wc_tree_id != new_tree_id {
let wc_tree = store.get_tree(&RepoPath::root(), &wc_tree_id)?;
let added_back = wc_tree.entries_matching(matcher.as_ref()).collect_vec();

View file

@ -379,7 +379,7 @@ pub fn edit_diff(
std::fs::remove_file(instructions_path).ok();
}
right_tree_state.snapshot(base_ignores)?;
right_tree_state.snapshot(base_ignores, None)?;
Ok(right_tree_state.current_tree_id().clone())
}