Fix reloading of git repositories
Also, clean up logic for reloading git repositories.
This commit is contained in:
parent
4424dafcd7
commit
d3477f75ac
1 changed files with 164 additions and 208 deletions
|
@ -239,13 +239,6 @@ pub struct LocalRepositoryEntry {
|
||||||
pub(crate) git_dir_path: Arc<Path>,
|
pub(crate) git_dir_path: Arc<Path>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LocalRepositoryEntry {
|
|
||||||
// Note that this path should be relative to the worktree root.
|
|
||||||
pub(crate) fn in_dot_git(&self, path: &Path) -> bool {
|
|
||||||
path.starts_with(self.git_dir_path.as_ref())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for LocalSnapshot {
|
impl Deref for LocalSnapshot {
|
||||||
type Target = Snapshot;
|
type Target = Snapshot;
|
||||||
|
|
||||||
|
@ -1850,15 +1843,6 @@ impl LocalSnapshot {
|
||||||
Some((path, self.git_repositories.get(&repo.work_directory_id())?))
|
Some((path, self.git_repositories.get(&repo.work_directory_id())?))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn repo_for_metadata(
|
|
||||||
&self,
|
|
||||||
path: &Path,
|
|
||||||
) -> Option<(&ProjectEntryId, &LocalRepositoryEntry)> {
|
|
||||||
self.git_repositories
|
|
||||||
.iter()
|
|
||||||
.find(|(_, repo)| repo.in_dot_git(path))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_update(
|
fn build_update(
|
||||||
&self,
|
&self,
|
||||||
project_id: u64,
|
project_id: u64,
|
||||||
|
@ -1994,57 +1978,6 @@ impl LocalSnapshot {
|
||||||
entry
|
entry
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use = "Changed paths must be used for diffing later"]
|
|
||||||
fn build_repo(&mut self, parent_path: Arc<Path>, fs: &dyn Fs) -> Option<Vec<Arc<Path>>> {
|
|
||||||
let abs_path = self.abs_path.join(&parent_path);
|
|
||||||
let work_dir: Arc<Path> = parent_path.parent().unwrap().into();
|
|
||||||
|
|
||||||
// Guard against repositories inside the repository metadata
|
|
||||||
if work_dir
|
|
||||||
.components()
|
|
||||||
.find(|component| component.as_os_str() == *DOT_GIT)
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let work_dir_id = self
|
|
||||||
.entry_for_path(work_dir.clone())
|
|
||||||
.map(|entry| entry.id)?;
|
|
||||||
|
|
||||||
if self.git_repositories.get(&work_dir_id).is_some() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let repo = fs.open_repo(abs_path.as_path())?;
|
|
||||||
let work_directory = RepositoryWorkDirectory(work_dir.clone());
|
|
||||||
|
|
||||||
let repo_lock = repo.lock();
|
|
||||||
|
|
||||||
self.repository_entries.insert(
|
|
||||||
work_directory.clone(),
|
|
||||||
RepositoryEntry {
|
|
||||||
work_directory: work_dir_id.into(),
|
|
||||||
branch: repo_lock.branch_name().map(Into::into),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let changed_paths = self.scan_statuses(repo_lock.deref(), &work_directory);
|
|
||||||
|
|
||||||
drop(repo_lock);
|
|
||||||
|
|
||||||
self.git_repositories.insert(
|
|
||||||
work_dir_id,
|
|
||||||
LocalRepositoryEntry {
|
|
||||||
git_dir_scan_id: 0,
|
|
||||||
repo_ptr: repo,
|
|
||||||
git_dir_path: parent_path.clone(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
Some(changed_paths)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use = "Changed paths must be used for diffing later"]
|
#[must_use = "Changed paths must be used for diffing later"]
|
||||||
fn scan_statuses(
|
fn scan_statuses(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -2215,10 +2148,7 @@ impl BackgroundScannerState {
|
||||||
self.reuse_entry_id(&mut entry);
|
self.reuse_entry_id(&mut entry);
|
||||||
let entry = self.snapshot.insert_entry(entry, fs);
|
let entry = self.snapshot.insert_entry(entry, fs);
|
||||||
if entry.path.file_name() == Some(&DOT_GIT) {
|
if entry.path.file_name() == Some(&DOT_GIT) {
|
||||||
let changed_paths = self.snapshot.build_repo(entry.path.clone(), fs);
|
self.build_repository(entry.path.clone(), fs);
|
||||||
if let Some(changed_paths) = changed_paths {
|
|
||||||
util::extend_sorted(&mut self.changed_paths, changed_paths, usize::MAX, Ord::cmp)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
entry
|
entry
|
||||||
}
|
}
|
||||||
|
@ -2283,10 +2213,7 @@ impl BackgroundScannerState {
|
||||||
self.snapshot.entries_by_id.edit(entries_by_id_edits, &());
|
self.snapshot.entries_by_id.edit(entries_by_id_edits, &());
|
||||||
|
|
||||||
if let Some(dotgit_path) = dotgit_path {
|
if let Some(dotgit_path) = dotgit_path {
|
||||||
let changed_paths = self.snapshot.build_repo(dotgit_path, fs);
|
self.build_repository(dotgit_path, fs);
|
||||||
if let Some(changed_paths) = changed_paths {
|
|
||||||
util::extend_sorted(&mut self.changed_paths, changed_paths, usize::MAX, Ord::cmp)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if let Err(ix) = self.changed_paths.binary_search(parent_path) {
|
if let Err(ix) = self.changed_paths.binary_search(parent_path) {
|
||||||
self.changed_paths.insert(ix, parent_path.clone());
|
self.changed_paths.insert(ix, parent_path.clone());
|
||||||
|
@ -2326,6 +2253,134 @@ impl BackgroundScannerState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reload_repositories(&mut self, changed_paths: &[Arc<Path>], fs: &dyn Fs) {
|
||||||
|
let scan_id = self.snapshot.scan_id;
|
||||||
|
|
||||||
|
// Find each of the .git directories that contain any of the given paths.
|
||||||
|
let mut prev_dot_git_dir = None;
|
||||||
|
for changed_path in changed_paths {
|
||||||
|
let Some(dot_git_dir) = changed_path
|
||||||
|
.ancestors()
|
||||||
|
.find(|ancestor| ancestor.file_name() == Some(&*DOT_GIT)) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Avoid processing the same repository multiple times, if multiple paths
|
||||||
|
// within it have changed.
|
||||||
|
if prev_dot_git_dir == Some(dot_git_dir) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
prev_dot_git_dir = Some(dot_git_dir);
|
||||||
|
|
||||||
|
// If there is already a repository for this .git directory, reload
|
||||||
|
// the status for all of its files.
|
||||||
|
let repository = self
|
||||||
|
.snapshot
|
||||||
|
.git_repositories
|
||||||
|
.iter()
|
||||||
|
.find_map(|(entry_id, repo)| {
|
||||||
|
(repo.git_dir_path.as_ref() == dot_git_dir).then(|| (*entry_id, repo.clone()))
|
||||||
|
});
|
||||||
|
match repository {
|
||||||
|
None => {
|
||||||
|
self.build_repository(dot_git_dir.into(), fs);
|
||||||
|
}
|
||||||
|
Some((entry_id, repository)) => {
|
||||||
|
if repository.git_dir_scan_id == scan_id {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let Some(work_dir) = self
|
||||||
|
.snapshot
|
||||||
|
.entry_for_id(entry_id)
|
||||||
|
.map(|entry| RepositoryWorkDirectory(entry.path.clone())) else { continue };
|
||||||
|
|
||||||
|
let repository = repository.repo_ptr.lock();
|
||||||
|
let branch = repository.branch_name();
|
||||||
|
repository.reload_index();
|
||||||
|
|
||||||
|
self.snapshot
|
||||||
|
.git_repositories
|
||||||
|
.update(&entry_id, |entry| entry.git_dir_scan_id = scan_id);
|
||||||
|
self.snapshot
|
||||||
|
.snapshot
|
||||||
|
.repository_entries
|
||||||
|
.update(&work_dir, |entry| entry.branch = branch.map(Into::into));
|
||||||
|
|
||||||
|
let changed_paths = self.snapshot.scan_statuses(&*repository, &work_dir);
|
||||||
|
util::extend_sorted(
|
||||||
|
&mut self.changed_paths,
|
||||||
|
changed_paths,
|
||||||
|
usize::MAX,
|
||||||
|
Ord::cmp,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any git repositories whose .git entry no longer exists.
|
||||||
|
let mut snapshot = &mut self.snapshot;
|
||||||
|
let mut repositories = mem::take(&mut snapshot.git_repositories);
|
||||||
|
let mut repository_entries = mem::take(&mut snapshot.repository_entries);
|
||||||
|
repositories.retain(|work_directory_id, _| {
|
||||||
|
snapshot
|
||||||
|
.entry_for_id(*work_directory_id)
|
||||||
|
.map_or(false, |entry| {
|
||||||
|
snapshot.entry_for_path(entry.path.join(*DOT_GIT)).is_some()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
repository_entries.retain(|_, entry| repositories.get(&entry.work_directory.0).is_some());
|
||||||
|
snapshot.git_repositories = repositories;
|
||||||
|
snapshot.repository_entries = repository_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_repository(&mut self, dot_git_path: Arc<Path>, fs: &dyn Fs) -> Option<()> {
|
||||||
|
let work_dir_path: Arc<Path> = dot_git_path.parent().unwrap().into();
|
||||||
|
|
||||||
|
// Guard against repositories inside the repository metadata
|
||||||
|
if work_dir_path.iter().any(|component| component == *DOT_GIT) {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
let work_dir_id = self
|
||||||
|
.snapshot
|
||||||
|
.entry_for_path(work_dir_path.clone())
|
||||||
|
.map(|entry| entry.id)?;
|
||||||
|
|
||||||
|
if self.snapshot.git_repositories.get(&work_dir_id).is_some() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let abs_path = self.snapshot.abs_path.join(&dot_git_path);
|
||||||
|
let repository = fs.open_repo(abs_path.as_path())?;
|
||||||
|
let work_directory = RepositoryWorkDirectory(work_dir_path.clone());
|
||||||
|
|
||||||
|
let repo_lock = repository.lock();
|
||||||
|
self.snapshot.repository_entries.insert(
|
||||||
|
work_directory.clone(),
|
||||||
|
RepositoryEntry {
|
||||||
|
work_directory: work_dir_id.into(),
|
||||||
|
branch: repo_lock.branch_name().map(Into::into),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let changed_paths = self
|
||||||
|
.snapshot
|
||||||
|
.scan_statuses(repo_lock.deref(), &work_directory);
|
||||||
|
drop(repo_lock);
|
||||||
|
|
||||||
|
self.snapshot.git_repositories.insert(
|
||||||
|
work_dir_id,
|
||||||
|
LocalRepositoryEntry {
|
||||||
|
git_dir_scan_id: 0,
|
||||||
|
repo_ptr: repository,
|
||||||
|
git_dir_path: dot_git_path.clone(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
util::extend_sorted(&mut self.changed_paths, changed_paths, usize::MAX, Ord::cmp);
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn build_gitignore(abs_path: &Path, fs: &dyn Fs) -> Result<Gitignore> {
|
async fn build_gitignore(abs_path: &Path, fs: &dyn Fs) -> Result<Gitignore> {
|
||||||
|
@ -3019,34 +3074,8 @@ impl BackgroundScanner {
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut state = self.state.lock();
|
let mut state = self.state.lock();
|
||||||
|
state.reload_repositories(&paths, self.fs.as_ref());
|
||||||
if let Some(paths) = paths {
|
state.snapshot.completed_scan_id = state.snapshot.scan_id;
|
||||||
for path in paths {
|
|
||||||
self.reload_git_repo(&path, &mut *state, self.fs.as_ref());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut snapshot = &mut state.snapshot;
|
|
||||||
|
|
||||||
let mut git_repositories = mem::take(&mut snapshot.git_repositories);
|
|
||||||
git_repositories.retain(|work_directory_id, _| {
|
|
||||||
snapshot
|
|
||||||
.entry_for_id(*work_directory_id)
|
|
||||||
.map_or(false, |entry| {
|
|
||||||
snapshot.entry_for_path(entry.path.join(*DOT_GIT)).is_some()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
snapshot.git_repositories = git_repositories;
|
|
||||||
|
|
||||||
let mut git_repository_entries = mem::take(&mut snapshot.snapshot.repository_entries);
|
|
||||||
git_repository_entries.retain(|_, entry| {
|
|
||||||
snapshot
|
|
||||||
.git_repositories
|
|
||||||
.get(&entry.work_directory.0)
|
|
||||||
.is_some()
|
|
||||||
});
|
|
||||||
snapshot.snapshot.repository_entries = git_repository_entries;
|
|
||||||
snapshot.completed_scan_id = snapshot.scan_id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.send_status_update(false, None);
|
self.send_status_update(false, None);
|
||||||
|
@ -3381,39 +3410,23 @@ impl BackgroundScanner {
|
||||||
root_canonical_path: PathBuf,
|
root_canonical_path: PathBuf,
|
||||||
mut abs_paths: Vec<PathBuf>,
|
mut abs_paths: Vec<PathBuf>,
|
||||||
scan_queue_tx: Option<Sender<ScanJob>>,
|
scan_queue_tx: Option<Sender<ScanJob>>,
|
||||||
) -> Option<Vec<Arc<Path>>> {
|
) -> Vec<Arc<Path>> {
|
||||||
let mut event_paths = Vec::<Arc<Path>>::with_capacity(abs_paths.len());
|
let mut event_paths = Vec::<Arc<Path>>::with_capacity(abs_paths.len());
|
||||||
abs_paths.sort_unstable();
|
abs_paths.sort_unstable();
|
||||||
abs_paths.dedup_by(|a, b| a.starts_with(&b));
|
abs_paths.dedup_by(|a, b| a.starts_with(&b));
|
||||||
{
|
abs_paths.retain(|abs_path| {
|
||||||
let state = self.state.lock();
|
if let Ok(path) = abs_path.strip_prefix(&root_canonical_path) {
|
||||||
abs_paths.retain(|abs_path| {
|
|
||||||
let path = if let Ok(path) = abs_path.strip_prefix(&root_canonical_path) {
|
|
||||||
path
|
|
||||||
} else {
|
|
||||||
log::error!(
|
|
||||||
"unexpected event {:?} for root path {:?}",
|
|
||||||
abs_path,
|
|
||||||
root_canonical_path
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(parent) = path.parent() {
|
|
||||||
if state
|
|
||||||
.snapshot
|
|
||||||
.entry_for_path(parent)
|
|
||||||
.map_or(true, |entry| entry.kind != EntryKind::Dir)
|
|
||||||
{
|
|
||||||
log::info!("ignoring event within unloaded directory {:?}", parent);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
event_paths.push(path.into());
|
event_paths.push(path.into());
|
||||||
return true;
|
true
|
||||||
});
|
} else {
|
||||||
}
|
log::error!(
|
||||||
|
"unexpected event {:?} for root path {:?}",
|
||||||
|
abs_path,
|
||||||
|
root_canonical_path
|
||||||
|
);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let metadata = futures::future::join_all(
|
let metadata = futures::future::join_all(
|
||||||
abs_paths
|
abs_paths
|
||||||
|
@ -3433,8 +3446,8 @@ impl BackgroundScanner {
|
||||||
|
|
||||||
let mut state = self.state.lock();
|
let mut state = self.state.lock();
|
||||||
let snapshot = &mut state.snapshot;
|
let snapshot = &mut state.snapshot;
|
||||||
let doing_recursive_update = scan_queue_tx.is_some();
|
|
||||||
let is_idle = snapshot.completed_scan_id == snapshot.scan_id;
|
let is_idle = snapshot.completed_scan_id == snapshot.scan_id;
|
||||||
|
let doing_recursive_update = scan_queue_tx.is_some();
|
||||||
snapshot.scan_id += 1;
|
snapshot.scan_id += 1;
|
||||||
if is_idle && !doing_recursive_update {
|
if is_idle && !doing_recursive_update {
|
||||||
snapshot.completed_scan_id = snapshot.scan_id;
|
snapshot.completed_scan_id = snapshot.scan_id;
|
||||||
|
@ -3449,7 +3462,21 @@ impl BackgroundScanner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (path, metadata) in event_paths.iter().cloned().zip(metadata.into_iter()) {
|
for (path, metadata) in event_paths.iter().zip(metadata.iter()) {
|
||||||
|
if let (Some(parent), true) = (path.parent(), doing_recursive_update) {
|
||||||
|
if state
|
||||||
|
.snapshot
|
||||||
|
.entry_for_path(parent)
|
||||||
|
.map_or(true, |entry| entry.kind != EntryKind::Dir)
|
||||||
|
{
|
||||||
|
log::debug!(
|
||||||
|
"ignoring event {path:?} within unloaded directory {:?}",
|
||||||
|
parent
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let abs_path: Arc<Path> = root_abs_path.join(&path).into();
|
let abs_path: Arc<Path> = root_abs_path.join(&path).into();
|
||||||
|
|
||||||
match metadata {
|
match metadata {
|
||||||
|
@ -3460,7 +3487,7 @@ impl BackgroundScanner {
|
||||||
|
|
||||||
let mut fs_entry = Entry::new(
|
let mut fs_entry = Entry::new(
|
||||||
path.clone(),
|
path.clone(),
|
||||||
&metadata,
|
metadata,
|
||||||
self.next_entry_id.as_ref(),
|
self.next_entry_id.as_ref(),
|
||||||
state.snapshot.root_char_bag,
|
state.snapshot.root_char_bag,
|
||||||
);
|
);
|
||||||
|
@ -3492,7 +3519,7 @@ impl BackgroundScanner {
|
||||||
ancestor_inodes.insert(metadata.inode);
|
ancestor_inodes.insert(metadata.inode);
|
||||||
smol::block_on(scan_queue_tx.send(ScanJob {
|
smol::block_on(scan_queue_tx.send(ScanJob {
|
||||||
abs_path,
|
abs_path,
|
||||||
path,
|
path: path.clone(),
|
||||||
ignore_stack,
|
ignore_stack,
|
||||||
ancestor_inodes,
|
ancestor_inodes,
|
||||||
is_external: fs_entry.is_external,
|
is_external: fs_entry.is_external,
|
||||||
|
@ -3519,7 +3546,7 @@ impl BackgroundScanner {
|
||||||
Ord::cmp,
|
Ord::cmp,
|
||||||
);
|
);
|
||||||
|
|
||||||
Some(event_paths)
|
event_paths
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_repo_path(&self, path: &Path, snapshot: &mut LocalSnapshot) -> Option<()> {
|
fn remove_repo_path(&self, path: &Path, snapshot: &mut LocalSnapshot) -> Option<()> {
|
||||||
|
@ -3544,77 +3571,6 @@ impl BackgroundScanner {
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reload_git_repo(
|
|
||||||
&self,
|
|
||||||
path: &Path,
|
|
||||||
state: &mut BackgroundScannerState,
|
|
||||||
fs: &dyn Fs,
|
|
||||||
) -> Option<()> {
|
|
||||||
let scan_id = state.snapshot.scan_id;
|
|
||||||
|
|
||||||
if path
|
|
||||||
.components()
|
|
||||||
.any(|component| component.as_os_str() == *DOT_GIT)
|
|
||||||
{
|
|
||||||
let (entry_id, repo_ptr) = {
|
|
||||||
let Some((entry_id, repo)) = state.snapshot.repo_for_metadata(&path) else {
|
|
||||||
let dot_git_dir = path.ancestors()
|
|
||||||
.skip_while(|ancestor| ancestor.file_name() != Some(&*DOT_GIT))
|
|
||||||
.next()?;
|
|
||||||
|
|
||||||
let changed_paths = state.snapshot.build_repo(dot_git_dir.into(), fs);
|
|
||||||
if let Some(changed_paths) = changed_paths {
|
|
||||||
util::extend_sorted(
|
|
||||||
&mut state.changed_paths,
|
|
||||||
changed_paths,
|
|
||||||
usize::MAX,
|
|
||||||
Ord::cmp,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
if repo.git_dir_scan_id == scan_id {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*entry_id, repo.repo_ptr.to_owned())
|
|
||||||
};
|
|
||||||
|
|
||||||
let work_dir = state
|
|
||||||
.snapshot
|
|
||||||
.entry_for_id(entry_id)
|
|
||||||
.map(|entry| RepositoryWorkDirectory(entry.path.clone()))?;
|
|
||||||
|
|
||||||
let repo = repo_ptr.lock();
|
|
||||||
repo.reload_index();
|
|
||||||
let branch = repo.branch_name();
|
|
||||||
|
|
||||||
state.snapshot.git_repositories.update(&entry_id, |entry| {
|
|
||||||
entry.git_dir_scan_id = scan_id;
|
|
||||||
});
|
|
||||||
|
|
||||||
state
|
|
||||||
.snapshot
|
|
||||||
.snapshot
|
|
||||||
.repository_entries
|
|
||||||
.update(&work_dir, |entry| {
|
|
||||||
entry.branch = branch.map(Into::into);
|
|
||||||
});
|
|
||||||
|
|
||||||
let changed_paths = state.snapshot.scan_statuses(repo.deref(), &work_dir);
|
|
||||||
|
|
||||||
util::extend_sorted(
|
|
||||||
&mut state.changed_paths,
|
|
||||||
changed_paths,
|
|
||||||
usize::MAX,
|
|
||||||
Ord::cmp,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn update_ignore_statuses(&self) {
|
async fn update_ignore_statuses(&self) {
|
||||||
use futures::FutureExt as _;
|
use futures::FutureExt as _;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue