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 | 13 | dirstate::SIZE_FROM_OTHER_PARENT, |
|
14 | 14 | filepatterns::PatternFileWarning, |
|
15 | 15 | matchers::{get_ignore_function, Matcher, VisitChildrenSet}, |
|
16 | operations::Operation, | |
|
16 | 17 | utils::{ |
|
17 | 18 | files::{find_dirs, HgMetadata}, |
|
18 | 19 | hg_path::{ |
@@ -101,7 +102,7 b" type IgnoreFnType<'a> = Box<dyn for<'r> " | |||
|
101 | 102 | |
|
102 | 103 | /// We have a good mix of owned (from directory traversal) and borrowed (from |
|
103 | 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 | 107 | /// A path with its computed ``Dispatch`` information |
|
107 | 108 | type DispatchedPath<'a> = (HgPathCow<'a>, Dispatch); |
@@ -294,9 +295,9 b' impl ToString for StatusError {' | |||
|
294 | 295 | /// and how, compared to the revision we're based on |
|
295 | 296 | pub struct Status<'a, M: Matcher + Sync> { |
|
296 | 297 | dmap: &'a DirstateMap, |
|
297 | matcher: &'a M, | |
|
298 | pub(crate) matcher: &'a M, | |
|
298 | 299 | root_dir: PathBuf, |
|
299 | options: StatusOptions, | |
|
300 | pub(crate) options: StatusOptions, | |
|
300 | 301 | ignore_fn: IgnoreFnType<'a>, |
|
301 | 302 | } |
|
302 | 303 | |
@@ -708,7 +709,7 b' where' | |||
|
708 | 709 | /// This takes a mutable reference to the results to account for the |
|
709 | 710 | /// `extend` in timings |
|
710 | 711 | #[timed] |
|
711 | fn handle_unknowns( | |
|
712 | pub fn handle_unknowns( | |
|
712 | 713 | &self, |
|
713 | 714 | results: &mut Vec<DispatchedPath<'a>>, |
|
714 | 715 | ) -> IoResult<()> { |
@@ -787,7 +788,7 b' where' | |||
|
787 | 788 | /// This takes a mutable reference to the results to account for the |
|
788 | 789 | /// `extend` in timings |
|
789 | 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 | 792 | results.par_extend(self.dmap.par_iter().flat_map( |
|
792 | 793 | move |(filename, entry)| { |
|
793 | 794 | let filename: &HgPath = filename; |
@@ -837,7 +838,7 b' where' | |||
|
837 | 838 | } |
|
838 | 839 | |
|
839 | 840 | #[timed] |
|
840 | fn build_response<'a>( | |
|
841 | pub fn build_response<'a>( | |
|
841 | 842 | results: impl IntoIterator<Item = DispatchedPath<'a>>, |
|
842 | 843 | traversed: Vec<HgPathBuf>, |
|
843 | 844 | ) -> (Vec<HgPathCow<'a>>, DirstateStatus<'a>) { |
@@ -899,56 +900,8 b" pub fn status<'a>(" | |||
|
899 | 900 | (Vec<HgPathCow<'a>>, DirstateStatus<'a>), |
|
900 | 901 | Vec<PatternFileWarning>, |
|
901 | 902 | )> { |
|
902 | let (traversed_sender, traversed_receiver) = | |
|
903 | crossbeam::channel::unbounded(); | |
|
904 | let (st, warnings) = | |
|
903 | let (status, warnings) = | |
|
905 | 904 | Status::new(dmap, matcher, root_dir, ignore_files, options)?; |
|
906 | 905 | |
|
907 | // Step 1: check the files explicitly mentioned by the user | |
|
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 | } | |
|
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)) | |
|
906 | Ok((status.run()?, warnings)) | |
|
954 | 907 | } |
General Comments 0
You need to be logged in to leave comments.
Login now