Show More
@@ -221,6 +221,7 b" fn walk_explicit<'a>(" | |||||
221 | dmap: &'a DirstateMap, |
|
221 | dmap: &'a DirstateMap, | |
222 | root_dir: impl AsRef<Path> + Sync + Send + 'a, |
|
222 | root_dir: impl AsRef<Path> + Sync + Send + 'a, | |
223 | options: StatusOptions, |
|
223 | options: StatusOptions, | |
|
224 | traversed_sender: crossbeam::Sender<HgPathBuf>, | |||
224 | ) -> impl ParallelIterator<Item = IoResult<(&'a HgPath, Dispatch)>> { |
|
225 | ) -> impl ParallelIterator<Item = IoResult<(&'a HgPath, Dispatch)>> { | |
225 | files |
|
226 | files | |
226 | .unwrap_or(&DEFAULT_WORK) |
|
227 | .unwrap_or(&DEFAULT_WORK) | |
@@ -255,6 +256,13 b" fn walk_explicit<'a>(" | |||||
255 | Some(Ok((normalized, Dispatch::Unknown))) |
|
256 | Some(Ok((normalized, Dispatch::Unknown))) | |
256 | } else { |
|
257 | } else { | |
257 | if file_type.is_dir() { |
|
258 | if file_type.is_dir() { | |
|
259 | if options.collect_traversed_dirs { | |||
|
260 | // The receiver always outlives the sender, | |||
|
261 | // so unwrap. | |||
|
262 | traversed_sender | |||
|
263 | .send(normalized.to_owned()) | |||
|
264 | .unwrap() | |||
|
265 | } | |||
258 | Some(Ok(( |
|
266 | Some(Ok(( | |
259 | normalized, |
|
267 | normalized, | |
260 | Dispatch::Directory { |
|
268 | Dispatch::Directory { | |
@@ -302,6 +310,9 b' pub struct StatusOptions {' | |||||
302 | pub list_clean: bool, |
|
310 | pub list_clean: bool, | |
303 | pub list_unknown: bool, |
|
311 | pub list_unknown: bool, | |
304 | pub list_ignored: bool, |
|
312 | pub list_ignored: bool, | |
|
313 | /// Whether to collect traversed dirs for applying a callback later. | |||
|
314 | /// Used by `hg purge` for example. | |||
|
315 | pub collect_traversed_dirs: bool, | |||
305 | } |
|
316 | } | |
306 |
|
317 | |||
307 | /// Dispatch a single entry (file, folder, symlink...) found during `traverse`. |
|
318 | /// Dispatch a single entry (file, folder, symlink...) found during `traverse`. | |
@@ -319,6 +330,7 b" fn handle_traversed_entry<'a>(" | |||||
319 | options: StatusOptions, |
|
330 | options: StatusOptions, | |
320 | filename: HgPathBuf, |
|
331 | filename: HgPathBuf, | |
321 | dir_entry: DirEntry, |
|
332 | dir_entry: DirEntry, | |
|
333 | traversed_sender: crossbeam::Sender<HgPathBuf>, | |||
322 | ) -> IoResult<()> { |
|
334 | ) -> IoResult<()> { | |
323 | let file_type = dir_entry.file_type()?; |
|
335 | let file_type = dir_entry.file_type()?; | |
324 | let entry_option = dmap.get(&filename); |
|
336 | let entry_option = dmap.get(&filename); | |
@@ -341,6 +353,7 b" fn handle_traversed_entry<'a>(" | |||||
341 | options, |
|
353 | options, | |
342 | entry_option, |
|
354 | entry_option, | |
343 | filename, |
|
355 | filename, | |
|
356 | traversed_sender, | |||
344 | ); |
|
357 | ); | |
345 | } else if file_type.is_file() || file_type.is_symlink() { |
|
358 | } else if file_type.is_file() || file_type.is_symlink() { | |
346 | if let Some(entry) = entry_option { |
|
359 | if let Some(entry) = entry_option { | |
@@ -407,6 +420,7 b" fn handle_traversed_dir<'a>(" | |||||
407 | options: StatusOptions, |
|
420 | options: StatusOptions, | |
408 | entry_option: Option<&'a DirstateEntry>, |
|
421 | entry_option: Option<&'a DirstateEntry>, | |
409 | directory: HgPathBuf, |
|
422 | directory: HgPathBuf, | |
|
423 | traversed_sender: crossbeam::Sender<HgPathBuf>, | |||
410 | ) { |
|
424 | ) { | |
411 | scope.spawn(move |_| { |
|
425 | scope.spawn(move |_| { | |
412 | // Nested `if` until `rust-lang/rust#53668` is stable |
|
426 | // Nested `if` until `rust-lang/rust#53668` is stable | |
@@ -433,6 +447,7 b" fn handle_traversed_dir<'a>(" | |||||
433 | ignore_fn, |
|
447 | ignore_fn, | |
434 | dir_ignore_fn, |
|
448 | dir_ignore_fn, | |
435 | options, |
|
449 | options, | |
|
450 | traversed_sender, | |||
436 | ) |
|
451 | ) | |
437 | .unwrap_or_else(|e| files_sender.send(Err(e)).unwrap()) |
|
452 | .unwrap_or_else(|e| files_sender.send(Err(e)).unwrap()) | |
438 | } |
|
453 | } | |
@@ -451,9 +466,15 b" fn traverse_dir<'a>(" | |||||
451 | ignore_fn: &IgnoreFnType, |
|
466 | ignore_fn: &IgnoreFnType, | |
452 | dir_ignore_fn: &IgnoreFnType, |
|
467 | dir_ignore_fn: &IgnoreFnType, | |
453 | options: StatusOptions, |
|
468 | options: StatusOptions, | |
|
469 | traversed_sender: crossbeam::Sender<HgPathBuf>, | |||
454 | ) -> IoResult<()> { |
|
470 | ) -> IoResult<()> { | |
455 | let directory = directory.as_ref(); |
|
471 | let directory = directory.as_ref(); | |
456 |
|
472 | |||
|
473 | if options.collect_traversed_dirs { | |||
|
474 | // The receiver always outlives the sender, so unwrap. | |||
|
475 | traversed_sender.send(directory.to_owned()).unwrap() | |||
|
476 | } | |||
|
477 | ||||
457 | let visit_entries = match matcher.visit_children_set(directory) { |
|
478 | let visit_entries = match matcher.visit_children_set(directory) { | |
458 | VisitChildrenSet::Empty => return Ok(()), |
|
479 | VisitChildrenSet::Empty => return Ok(()), | |
459 | VisitChildrenSet::This | VisitChildrenSet::Recursive => None, |
|
480 | VisitChildrenSet::This | VisitChildrenSet::Recursive => None, | |
@@ -510,6 +531,7 b" fn traverse_dir<'a>(" | |||||
510 | options, |
|
531 | options, | |
511 | filename, |
|
532 | filename, | |
512 | dir_entry, |
|
533 | dir_entry, | |
|
534 | traversed_sender.clone(), | |||
513 | )?; |
|
535 | )?; | |
514 | } |
|
536 | } | |
515 | } |
|
537 | } | |
@@ -533,6 +555,7 b" fn traverse<'a>(" | |||||
533 | dir_ignore_fn: &IgnoreFnType, |
|
555 | dir_ignore_fn: &IgnoreFnType, | |
534 | options: StatusOptions, |
|
556 | options: StatusOptions, | |
535 | results: &mut Vec<(Cow<'a, HgPath>, Dispatch)>, |
|
557 | results: &mut Vec<(Cow<'a, HgPath>, Dispatch)>, | |
|
558 | traversed_sender: crossbeam::Sender<HgPathBuf>, | |||
536 | ) -> IoResult<()> { |
|
559 | ) -> IoResult<()> { | |
537 | let root_dir = root_dir.as_ref(); |
|
560 | let root_dir = root_dir.as_ref(); | |
538 |
|
561 | |||
@@ -550,6 +573,7 b" fn traverse<'a>(" | |||||
550 | &ignore_fn, |
|
573 | &ignore_fn, | |
551 | &dir_ignore_fn, |
|
574 | &dir_ignore_fn, | |
552 | options, |
|
575 | options, | |
|
576 | traversed_sender, | |||
553 | )?; |
|
577 | )?; | |
554 |
|
578 | |||
555 | // Disconnect the channel so the receiver stops waiting |
|
579 | // Disconnect the channel so the receiver stops waiting | |
@@ -640,11 +664,14 b" pub struct DirstateStatus<'a> {" | |||||
640 | pub ignored: Vec<Cow<'a, HgPath>>, |
|
664 | pub ignored: Vec<Cow<'a, HgPath>>, | |
641 | pub unknown: Vec<Cow<'a, HgPath>>, |
|
665 | pub unknown: Vec<Cow<'a, HgPath>>, | |
642 | pub bad: Vec<(Cow<'a, HgPath>, BadMatch)>, |
|
666 | pub bad: Vec<(Cow<'a, HgPath>, BadMatch)>, | |
|
667 | /// Only filled if `collect_traversed_dirs` is `true` | |||
|
668 | pub traversed: Vec<HgPathBuf>, | |||
643 | } |
|
669 | } | |
644 |
|
670 | |||
645 | #[timed] |
|
671 | #[timed] | |
646 | fn build_response<'a>( |
|
672 | fn build_response<'a>( | |
647 | results: impl IntoIterator<Item = (Cow<'a, HgPath>, Dispatch)>, |
|
673 | results: impl IntoIterator<Item = (Cow<'a, HgPath>, Dispatch)>, | |
|
674 | traversed: Vec<HgPathBuf>, | |||
648 | ) -> (Vec<Cow<'a, HgPath>>, DirstateStatus<'a>) { |
|
675 | ) -> (Vec<Cow<'a, HgPath>>, DirstateStatus<'a>) { | |
649 | let mut lookup = vec![]; |
|
676 | let mut lookup = vec![]; | |
650 | let mut modified = vec![]; |
|
677 | let mut modified = vec![]; | |
@@ -683,6 +710,7 b" fn build_response<'a>(" | |||||
683 | ignored, |
|
710 | ignored, | |
684 | unknown, |
|
711 | unknown, | |
685 | bad, |
|
712 | bad, | |
|
713 | traversed, | |||
686 | }, |
|
714 | }, | |
687 | ) |
|
715 | ) | |
688 | } |
|
716 | } | |
@@ -849,8 +877,17 b" pub fn status<'a: 'c, 'b: 'c, 'c>(" | |||||
849 |
|
877 | |||
850 | let files = matcher.file_set(); |
|
878 | let files = matcher.file_set(); | |
851 |
|
879 | |||
|
880 | // `crossbeam::Sender` is `Send`, while `mpsc::Sender` is not. | |||
|
881 | let (traversed_sender, traversed_recv) = crossbeam::channel::unbounded(); | |||
|
882 | ||||
852 | // Step 1: check the files explicitly mentioned by the user |
|
883 | // Step 1: check the files explicitly mentioned by the user | |
853 |
let explicit = walk_explicit( |
|
884 | let explicit = walk_explicit( | |
|
885 | files, | |||
|
886 | &dmap, | |||
|
887 | root_dir, | |||
|
888 | options, | |||
|
889 | traversed_sender.clone(), | |||
|
890 | ); | |||
854 |
|
891 | |||
855 | // Collect results into a `Vec` because we do very few lookups in most |
|
892 | // Collect results into a `Vec` because we do very few lookups in most | |
856 | // cases. |
|
893 | // cases. | |
@@ -888,6 +925,7 b" pub fn status<'a: 'c, 'b: 'c, 'c>(" | |||||
888 | &dir_ignore_fn, |
|
925 | &dir_ignore_fn, | |
889 | options, |
|
926 | options, | |
890 | &mut results, |
|
927 | &mut results, | |
|
928 | traversed_sender.clone(), | |||
891 | )?; |
|
929 | )?; | |
892 | } |
|
930 | } | |
893 | } |
|
931 | } | |
@@ -911,5 +949,9 b" pub fn status<'a: 'c, 'b: 'c, 'c>(" | |||||
911 | } |
|
949 | } | |
912 | } |
|
950 | } | |
913 |
|
951 | |||
914 | Ok((build_response(results), warnings)) |
|
952 | // Close the channel | |
|
953 | drop(traversed_sender); | |||
|
954 | let traversed_dirs = traversed_recv.into_iter().collect(); | |||
|
955 | ||||
|
956 | Ok((build_response(results, traversed_dirs), warnings)) | |||
915 | } |
|
957 | } |
General Comments 0
You need to be logged in to leave comments.
Login now