##// END OF EJS Templates
hg-core: define a `dirstate_status` `Operation`...
Raphaël Gomès -
r45673:98817e5d default
parent child Browse files
Show More
@@ -0,0 +1,76 b''
1 // dirstate_status.rs
2 //
3 // Copyright 2019, Raphaël Gomès <rgomes@octobus.net>
4 //
5 // This software may be used and distributed according to the terms of the
6 // GNU General Public License version 2 or any later version.
7
8 use crate::dirstate::status::{build_response, Dispatch, HgPathCow, Status};
9 use crate::matchers::Matcher;
10 use crate::operations::Operation;
11 use crate::{DirstateStatus, StatusError};
12
13 /// A tuple of the paths that need to be checked in the filelog because it's
14 /// ambiguous whether they've changed, and the rest of the already dispatched
15 /// files.
16 pub type LookupAndStatus<'a> = (Vec<HgPathCow<'a>>, DirstateStatus<'a>);
17
18 impl<'a, M: Matcher + Sync> Operation<LookupAndStatus<'a>> for Status<'a, M> {
19 type Error = StatusError;
20
21 fn run(&self) -> Result<LookupAndStatus<'a>, Self::Error> {
22 let (traversed_sender, traversed_receiver) =
23 crossbeam::channel::unbounded();
24
25 // Step 1: check the files explicitly mentioned by the user
26 let (work, mut results) = self.walk_explicit(traversed_sender.clone());
27
28 if !work.is_empty() {
29 // Hashmaps are quite a bit slower to build than vecs, so only
30 // build it if needed.
31 let old_results = results.iter().cloned().collect();
32
33 // Step 2: recursively check the working directory for changes if
34 // needed
35 for (dir, dispatch) in work {
36 match dispatch {
37 Dispatch::Directory { was_file } => {
38 if was_file {
39 results.push((dir.to_owned(), Dispatch::Removed));
40 }
41 if self.options.list_ignored
42 || self.options.list_unknown
43 && !self.dir_ignore(&dir)
44 {
45 self.traverse(
46 &dir,
47 &old_results,
48 &mut results,
49 traversed_sender.clone(),
50 )?;
51 }
52 }
53 _ => {
54 unreachable!("There can only be directories in `work`")
55 }
56 }
57 }
58 }
59
60 if !self.matcher.is_exact() {
61 if self.options.list_unknown {
62 self.handle_unknowns(&mut results)?;
63 } else {
64 // TODO this is incorrect, see issue6335
65 // This requires a fix in both Python and Rust that can happen
66 // with other pending changes to `status`.
67 self.extend_from_dmap(&mut results);
68 }
69 }
70
71 drop(traversed_sender);
72 let traversed = traversed_receiver.into_iter().collect();
73
74 Ok(build_response(results, traversed))
75 }
76 }
@@ -13,6 +13,7 b' use crate::{'
13 dirstate::SIZE_FROM_OTHER_PARENT,
13 dirstate::SIZE_FROM_OTHER_PARENT,
14 filepatterns::PatternFileWarning,
14 filepatterns::PatternFileWarning,
15 matchers::{get_ignore_function, Matcher, VisitChildrenSet},
15 matchers::{get_ignore_function, Matcher, VisitChildrenSet},
16 operations::Operation,
16 utils::{
17 utils::{
17 files::{find_dirs, HgMetadata},
18 files::{find_dirs, HgMetadata},
18 hg_path::{
19 hg_path::{
@@ -101,7 +102,7 b" type IgnoreFnType<'a> = Box<dyn for<'r> "
101
102
102 /// We have a good mix of owned (from directory traversal) and borrowed (from
103 /// We have a good mix of owned (from directory traversal) and borrowed (from
103 /// the dirstate/explicit) paths, this comes up a lot.
104 /// the dirstate/explicit) paths, this comes up a lot.
104 type HgPathCow<'a> = Cow<'a, HgPath>;
105 pub type HgPathCow<'a> = Cow<'a, HgPath>;
105
106
106 /// A path with its computed ``Dispatch`` information
107 /// A path with its computed ``Dispatch`` information
107 type DispatchedPath<'a> = (HgPathCow<'a>, Dispatch);
108 type DispatchedPath<'a> = (HgPathCow<'a>, Dispatch);
@@ -294,9 +295,9 b' impl ToString for StatusError {'
294 /// and how, compared to the revision we're based on
295 /// and how, compared to the revision we're based on
295 pub struct Status<'a, M: Matcher + Sync> {
296 pub struct Status<'a, M: Matcher + Sync> {
296 dmap: &'a DirstateMap,
297 dmap: &'a DirstateMap,
297 matcher: &'a M,
298 pub(crate) matcher: &'a M,
298 root_dir: PathBuf,
299 root_dir: PathBuf,
299 options: StatusOptions,
300 pub(crate) options: StatusOptions,
300 ignore_fn: IgnoreFnType<'a>,
301 ignore_fn: IgnoreFnType<'a>,
301 }
302 }
302
303
@@ -708,7 +709,7 b' where'
708 /// This takes a mutable reference to the results to account for the
709 /// This takes a mutable reference to the results to account for the
709 /// `extend` in timings
710 /// `extend` in timings
710 #[timed]
711 #[timed]
711 fn handle_unknowns(
712 pub fn handle_unknowns(
712 &self,
713 &self,
713 results: &mut Vec<DispatchedPath<'a>>,
714 results: &mut Vec<DispatchedPath<'a>>,
714 ) -> IoResult<()> {
715 ) -> IoResult<()> {
@@ -787,7 +788,7 b' where'
787 /// This takes a mutable reference to the results to account for the
788 /// This takes a mutable reference to the results to account for the
788 /// `extend` in timings
789 /// `extend` in timings
789 #[timed]
790 #[timed]
790 fn extend_from_dmap(&self, results: &mut Vec<DispatchedPath<'a>>) {
791 pub fn extend_from_dmap(&self, results: &mut Vec<DispatchedPath<'a>>) {
791 results.par_extend(self.dmap.par_iter().flat_map(
792 results.par_extend(self.dmap.par_iter().flat_map(
792 move |(filename, entry)| {
793 move |(filename, entry)| {
793 let filename: &HgPath = filename;
794 let filename: &HgPath = filename;
@@ -837,7 +838,7 b' where'
837 }
838 }
838
839
839 #[timed]
840 #[timed]
840 fn build_response<'a>(
841 pub fn build_response<'a>(
841 results: impl IntoIterator<Item = DispatchedPath<'a>>,
842 results: impl IntoIterator<Item = DispatchedPath<'a>>,
842 traversed: Vec<HgPathBuf>,
843 traversed: Vec<HgPathBuf>,
843 ) -> (Vec<HgPathCow<'a>>, DirstateStatus<'a>) {
844 ) -> (Vec<HgPathCow<'a>>, DirstateStatus<'a>) {
@@ -899,56 +900,8 b" pub fn status<'a>("
899 (Vec<HgPathCow<'a>>, DirstateStatus<'a>),
900 (Vec<HgPathCow<'a>>, DirstateStatus<'a>),
900 Vec<PatternFileWarning>,
901 Vec<PatternFileWarning>,
901 )> {
902 )> {
902 let (traversed_sender, traversed_receiver) =
903 let (status, warnings) =
903 crossbeam::channel::unbounded();
904 let (st, warnings) =
905 Status::new(dmap, matcher, root_dir, ignore_files, options)?;
904 Status::new(dmap, matcher, root_dir, ignore_files, options)?;
906
905
907 // Step 1: check the files explicitly mentioned by the user
906 Ok((status.run()?, warnings))
908 let (work, mut results) = st.walk_explicit(traversed_sender.clone());
909
910 if !work.is_empty() {
911 // Hashmaps are quite a bit slower to build than vecs, so only build it
912 // if needed.
913 let old_results = results.iter().cloned().collect();
914
915 // Step 2: recursively check the working directory for changes if
916 // needed
917 for (dir, dispatch) in work {
918 match dispatch {
919 Dispatch::Directory { was_file } => {
920 if was_file {
921 results.push((dir.to_owned(), Dispatch::Removed));
922 }
907 }
923 if options.list_ignored
924 || options.list_unknown && !st.dir_ignore(&dir)
925 {
926 st.traverse(
927 &dir,
928 &old_results,
929 &mut results,
930 traversed_sender.clone(),
931 )?;
932 }
933 }
934 _ => unreachable!("There can only be directories in `work`"),
935 }
936 }
937 }
938
939 if !matcher.is_exact() {
940 if options.list_unknown {
941 st.handle_unknowns(&mut results)?;
942 } else {
943 // TODO this is incorrect, see issue6335
944 // This requires a fix in both Python and Rust that can happen
945 // with other pending changes to `status`.
946 st.extend_from_dmap(&mut results);
947 }
948 }
949
950 drop(traversed_sender);
951 let traversed = traversed_receiver.into_iter().collect();
952
953 Ok((build_response(results, traversed), warnings))
954 }
@@ -1,3 +1,4 b''
1 mod dirstate_status;
1 mod find_root;
2 mod find_root;
2 pub use find_root::{FindRoot, FindRootError, FindRootErrorKind};
3 pub use find_root::{FindRoot, FindRootError, FindRootErrorKind};
3
4
General Comments 0
You need to be logged in to leave comments. Login now