Fix some syncing issues with git statuses (#25535)
Like the real app, this one infinite loops if you have a diff in an UnsharedFile. Release Notes: - N/A *or* Added/Fixed/Improved ... --------- Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
parent
88baf171c3
commit
08539b32d0
11 changed files with 283 additions and 6 deletions
|
@ -5,12 +5,20 @@ mod mac_watcher;
|
|||
pub mod fs_watcher;
|
||||
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
use collections::HashMap;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
use git::status::StatusCode;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
use git::status::TrackedStatus;
|
||||
use git::GitHostingProviderRegistry;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
use git::{repository::RepoPath, status::FileStatus};
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||
use ashpd::desktop::trash;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
use std::collections::HashSet;
|
||||
#[cfg(unix)]
|
||||
use std::os::fd::AsFd;
|
||||
#[cfg(unix)]
|
||||
|
@ -1292,6 +1300,105 @@ impl FakeFs {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn set_git_content_for_repo(
|
||||
&self,
|
||||
dot_git: &Path,
|
||||
head_state: &[(RepoPath, String, Option<String>)],
|
||||
) {
|
||||
self.with_git_state(dot_git, true, |state| {
|
||||
state.head_contents.clear();
|
||||
state.head_contents.extend(
|
||||
head_state
|
||||
.iter()
|
||||
.map(|(path, head_content, _)| (path.clone(), head_content.clone())),
|
||||
);
|
||||
state.index_contents.clear();
|
||||
state.index_contents.extend(head_state.iter().map(
|
||||
|(path, head_content, index_content)| {
|
||||
(
|
||||
path.clone(),
|
||||
index_content.as_ref().unwrap_or(head_content).clone(),
|
||||
)
|
||||
},
|
||||
));
|
||||
});
|
||||
self.recalculate_git_status(dot_git);
|
||||
}
|
||||
|
||||
pub fn recalculate_git_status(&self, dot_git: &Path) {
|
||||
let git_files: HashMap<_, _> = self
|
||||
.files()
|
||||
.iter()
|
||||
.filter_map(|path| {
|
||||
let repo_path =
|
||||
RepoPath::new(path.strip_prefix(dot_git.parent().unwrap()).ok()?.into());
|
||||
let content = self
|
||||
.read_file_sync(path)
|
||||
.ok()
|
||||
.map(|content| String::from_utf8(content).unwrap());
|
||||
Some((repo_path, content?))
|
||||
})
|
||||
.collect();
|
||||
self.with_git_state(dot_git, false, |state| {
|
||||
state.statuses.clear();
|
||||
let mut paths: HashSet<_> = state.head_contents.keys().collect();
|
||||
paths.extend(state.index_contents.keys());
|
||||
paths.extend(git_files.keys());
|
||||
for path in paths {
|
||||
let head = state.head_contents.get(path);
|
||||
let index = state.index_contents.get(path);
|
||||
let fs = git_files.get(path);
|
||||
let status = match (head, index, fs) {
|
||||
(Some(head), Some(index), Some(fs)) => FileStatus::Tracked(TrackedStatus {
|
||||
index_status: if head == index {
|
||||
StatusCode::Unmodified
|
||||
} else {
|
||||
StatusCode::Modified
|
||||
},
|
||||
worktree_status: if fs == index {
|
||||
StatusCode::Unmodified
|
||||
} else {
|
||||
StatusCode::Modified
|
||||
},
|
||||
}),
|
||||
(Some(head), Some(index), None) => FileStatus::Tracked(TrackedStatus {
|
||||
index_status: if head == index {
|
||||
StatusCode::Unmodified
|
||||
} else {
|
||||
StatusCode::Modified
|
||||
},
|
||||
worktree_status: StatusCode::Deleted,
|
||||
}),
|
||||
(Some(_), None, Some(_)) => FileStatus::Tracked(TrackedStatus {
|
||||
index_status: StatusCode::Deleted,
|
||||
worktree_status: StatusCode::Added,
|
||||
}),
|
||||
(Some(_), None, None) => FileStatus::Tracked(TrackedStatus {
|
||||
index_status: StatusCode::Deleted,
|
||||
worktree_status: StatusCode::Deleted,
|
||||
}),
|
||||
(None, Some(index), Some(fs)) => FileStatus::Tracked(TrackedStatus {
|
||||
index_status: StatusCode::Added,
|
||||
worktree_status: if fs == index {
|
||||
StatusCode::Unmodified
|
||||
} else {
|
||||
StatusCode::Modified
|
||||
},
|
||||
}),
|
||||
(None, Some(_), None) => FileStatus::Tracked(TrackedStatus {
|
||||
index_status: StatusCode::Added,
|
||||
worktree_status: StatusCode::Deleted,
|
||||
}),
|
||||
(None, None, Some(_)) => FileStatus::Untracked,
|
||||
(None, None, None) => {
|
||||
unreachable!();
|
||||
}
|
||||
};
|
||||
state.statuses.insert(path.clone(), status);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_blame_for_repo(&self, dot_git: &Path, blames: Vec<(RepoPath, git::blame::Blame)>) {
|
||||
self.with_git_state(dot_git, true, |state| {
|
||||
state.blames.clear();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue