Show More
@@ -221,6 +221,7 b" fn walk_explicit<'a>(" | |||
|
221 | 221 | dmap: &'a DirstateMap, |
|
222 | 222 | root_dir: impl AsRef<Path> + Sync + Send + 'a, |
|
223 | 223 | options: StatusOptions, |
|
224 | traversed_sender: crossbeam::Sender<HgPathBuf>, | |
|
224 | 225 | ) -> impl ParallelIterator<Item = IoResult<(&'a HgPath, Dispatch)>> { |
|
225 | 226 | files |
|
226 | 227 | .unwrap_or(&DEFAULT_WORK) |
@@ -255,6 +256,13 b" fn walk_explicit<'a>(" | |||
|
255 | 256 | Some(Ok((normalized, Dispatch::Unknown))) |
|
256 | 257 | } else { |
|
257 | 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 | 266 | Some(Ok(( |
|
259 | 267 | normalized, |
|
260 | 268 | Dispatch::Directory { |
@@ -302,6 +310,9 b' pub struct StatusOptions {' | |||
|
302 | 310 | pub list_clean: bool, |
|
303 | 311 | pub list_unknown: bool, |
|
304 | 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 | 318 | /// Dispatch a single entry (file, folder, symlink...) found during `traverse`. |
@@ -319,6 +330,7 b" fn handle_traversed_entry<'a>(" | |||
|
319 | 330 | options: StatusOptions, |
|
320 | 331 | filename: HgPathBuf, |
|
321 | 332 | dir_entry: DirEntry, |
|
333 | traversed_sender: crossbeam::Sender<HgPathBuf>, | |
|
322 | 334 | ) -> IoResult<()> { |
|
323 | 335 | let file_type = dir_entry.file_type()?; |
|
324 | 336 | let entry_option = dmap.get(&filename); |
@@ -341,6 +353,7 b" fn handle_traversed_entry<'a>(" | |||
|
341 | 353 | options, |
|
342 | 354 | entry_option, |
|
343 | 355 | filename, |
|
356 | traversed_sender, | |
|
344 | 357 | ); |
|
345 | 358 | } else if file_type.is_file() || file_type.is_symlink() { |
|
346 | 359 | if let Some(entry) = entry_option { |
@@ -407,6 +420,7 b" fn handle_traversed_dir<'a>(" | |||
|
407 | 420 | options: StatusOptions, |
|
408 | 421 | entry_option: Option<&'a DirstateEntry>, |
|
409 | 422 | directory: HgPathBuf, |
|
423 | traversed_sender: crossbeam::Sender<HgPathBuf>, | |
|
410 | 424 | ) { |
|
411 | 425 | scope.spawn(move |_| { |
|
412 | 426 | // Nested `if` until `rust-lang/rust#53668` is stable |
@@ -433,6 +447,7 b" fn handle_traversed_dir<'a>(" | |||
|
433 | 447 | ignore_fn, |
|
434 | 448 | dir_ignore_fn, |
|
435 | 449 | options, |
|
450 | traversed_sender, | |
|
436 | 451 | ) |
|
437 | 452 | .unwrap_or_else(|e| files_sender.send(Err(e)).unwrap()) |
|
438 | 453 | } |
@@ -451,9 +466,15 b" fn traverse_dir<'a>(" | |||
|
451 | 466 | ignore_fn: &IgnoreFnType, |
|
452 | 467 | dir_ignore_fn: &IgnoreFnType, |
|
453 | 468 | options: StatusOptions, |
|
469 | traversed_sender: crossbeam::Sender<HgPathBuf>, | |
|
454 | 470 | ) -> IoResult<()> { |
|
455 | 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 | 478 | let visit_entries = match matcher.visit_children_set(directory) { |
|
458 | 479 | VisitChildrenSet::Empty => return Ok(()), |
|
459 | 480 | VisitChildrenSet::This | VisitChildrenSet::Recursive => None, |
@@ -510,6 +531,7 b" fn traverse_dir<'a>(" | |||
|
510 | 531 | options, |
|
511 | 532 | filename, |
|
512 | 533 | dir_entry, |
|
534 | traversed_sender.clone(), | |
|
513 | 535 | )?; |
|
514 | 536 | } |
|
515 | 537 | } |
@@ -533,6 +555,7 b" fn traverse<'a>(" | |||
|
533 | 555 | dir_ignore_fn: &IgnoreFnType, |
|
534 | 556 | options: StatusOptions, |
|
535 | 557 | results: &mut Vec<(Cow<'a, HgPath>, Dispatch)>, |
|
558 | traversed_sender: crossbeam::Sender<HgPathBuf>, | |
|
536 | 559 | ) -> IoResult<()> { |
|
537 | 560 | let root_dir = root_dir.as_ref(); |
|
538 | 561 | |
@@ -550,6 +573,7 b" fn traverse<'a>(" | |||
|
550 | 573 | &ignore_fn, |
|
551 | 574 | &dir_ignore_fn, |
|
552 | 575 | options, |
|
576 | traversed_sender, | |
|
553 | 577 | )?; |
|
554 | 578 | |
|
555 | 579 | // Disconnect the channel so the receiver stops waiting |
@@ -640,11 +664,14 b" pub struct DirstateStatus<'a> {" | |||
|
640 | 664 | pub ignored: Vec<Cow<'a, HgPath>>, |
|
641 | 665 | pub unknown: Vec<Cow<'a, HgPath>>, |
|
642 | 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 | 671 | #[timed] |
|
646 | 672 | fn build_response<'a>( |
|
647 | 673 | results: impl IntoIterator<Item = (Cow<'a, HgPath>, Dispatch)>, |
|
674 | traversed: Vec<HgPathBuf>, | |
|
648 | 675 | ) -> (Vec<Cow<'a, HgPath>>, DirstateStatus<'a>) { |
|
649 | 676 | let mut lookup = vec![]; |
|
650 | 677 | let mut modified = vec![]; |
@@ -683,6 +710,7 b" fn build_response<'a>(" | |||
|
683 | 710 | ignored, |
|
684 | 711 | unknown, |
|
685 | 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 | 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 | 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 | 892 | // Collect results into a `Vec` because we do very few lookups in most |
|
856 | 893 | // cases. |
@@ -888,6 +925,7 b" pub fn status<'a: 'c, 'b: 'c, 'c>(" | |||
|
888 | 925 | &dir_ignore_fn, |
|
889 | 926 | options, |
|
890 | 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