Mercurial > public > mercurial-scm > hg-stable
diff rust/hg-core/src/operations/dirstate_status.rs @ 45113:98817e5daca7
hg-core: define a `dirstate_status` `Operation`
This is 3/3 in a series of patches to improve dirstate status' code.
Following in the footsteps of a46e36b82461, we move the main status
functionality to an `Operation`. This will most likely be subject to change in
the future (what function signature, what parameters, etc., but we will see
when `rhg` gets `hg status` support.
Differential Revision: https://phab.mercurial-scm.org/D8663
author | Rapha?l Gom?s <rgomes@octobus.net> |
---|---|
date | Wed, 24 Jun 2020 17:53:44 +0200 |
parents | |
children | 452ece5654c5 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/hg-core/src/operations/dirstate_status.rs Wed Jun 24 17:53:44 2020 +0200 @@ -0,0 +1,76 @@ +// dirstate_status.rs +// +// Copyright 2019, Raphaël Gomès <rgomes@octobus.net> +// +// This software may be used and distributed according to the terms of the +// GNU General Public License version 2 or any later version. + +use crate::dirstate::status::{build_response, Dispatch, HgPathCow, Status}; +use crate::matchers::Matcher; +use crate::operations::Operation; +use crate::{DirstateStatus, StatusError}; + +/// A tuple of the paths that need to be checked in the filelog because it's +/// ambiguous whether they've changed, and the rest of the already dispatched +/// files. +pub type LookupAndStatus<'a> = (Vec<HgPathCow<'a>>, DirstateStatus<'a>); + +impl<'a, M: Matcher + Sync> Operation<LookupAndStatus<'a>> for Status<'a, M> { + type Error = StatusError; + + fn run(&self) -> Result<LookupAndStatus<'a>, Self::Error> { + let (traversed_sender, traversed_receiver) = + crossbeam::channel::unbounded(); + + // Step 1: check the files explicitly mentioned by the user + let (work, mut results) = self.walk_explicit(traversed_sender.clone()); + + if !work.is_empty() { + // Hashmaps are quite a bit slower to build than vecs, so only + // build it if needed. + let old_results = results.iter().cloned().collect(); + + // Step 2: recursively check the working directory for changes if + // needed + for (dir, dispatch) in work { + match dispatch { + Dispatch::Directory { was_file } => { + if was_file { + results.push((dir.to_owned(), Dispatch::Removed)); + } + if self.options.list_ignored + || self.options.list_unknown + && !self.dir_ignore(&dir) + { + self.traverse( + &dir, + &old_results, + &mut results, + traversed_sender.clone(), + )?; + } + } + _ => { + unreachable!("There can only be directories in `work`") + } + } + } + } + + if !self.matcher.is_exact() { + if self.options.list_unknown { + self.handle_unknowns(&mut results)?; + } else { + // TODO this is incorrect, see issue6335 + // This requires a fix in both Python and Rust that can happen + // with other pending changes to `status`. + self.extend_from_dmap(&mut results); + } + } + + drop(traversed_sender); + let traversed = traversed_receiver.into_iter().collect(); + + Ok(build_response(results, traversed)) + } +}