Show More
@@ -109,6 +109,10 b" pub type HgPathCow<'a> = Cow<'a, HgPath>" | |||||
109 | /// A path with its computed ``Dispatch`` information |
|
109 | /// A path with its computed ``Dispatch`` information | |
110 | type DispatchedPath<'a> = (HgPathCow<'a>, Dispatch); |
|
110 | type DispatchedPath<'a> = (HgPathCow<'a>, Dispatch); | |
111 |
|
111 | |||
|
112 | /// The conversion from `HgPath` to a real fs path failed. | |||
|
113 | /// `22` is the error code for "Invalid argument" | |||
|
114 | const INVALID_PATH_DISPATCH: Dispatch = Dispatch::Bad(BadMatch::OsError(22)); | |||
|
115 | ||||
112 | /// Dates and times that are outside the 31-bit signed range are compared |
|
116 | /// Dates and times that are outside the 31-bit signed range are compared | |
113 | /// modulo 2^31. This should prevent hg from behaving badly with very large |
|
117 | /// modulo 2^31. This should prevent hg from behaving badly with very large | |
114 | /// files or corrupt dates while still having a high probability of detecting |
|
118 | /// files or corrupt dates while still having a high probability of detecting | |
@@ -217,6 +221,12 b' fn dispatch_missing(state: EntryState) -' | |||||
217 | } |
|
221 | } | |
218 | } |
|
222 | } | |
219 |
|
223 | |||
|
224 | fn dispatch_os_error(e: &std::io::Error) -> Dispatch { | |||
|
225 | Dispatch::Bad(BadMatch::OsError( | |||
|
226 | e.raw_os_error().expect("expected real OS error"), | |||
|
227 | )) | |||
|
228 | } | |||
|
229 | ||||
220 | lazy_static! { |
|
230 | lazy_static! { | |
221 | static ref DEFAULT_WORK: HashSet<&'static HgPath> = { |
|
231 | static ref DEFAULT_WORK: HashSet<&'static HgPath> = { | |
222 | let mut h = HashSet::new(); |
|
232 | let mut h = HashSet::new(); | |
@@ -372,13 +382,18 b' where' | |||||
372 | .file_set() |
|
382 | .file_set() | |
373 | .unwrap_or(&DEFAULT_WORK) |
|
383 | .unwrap_or(&DEFAULT_WORK) | |
374 | .par_iter() |
|
384 | .par_iter() | |
375 |
.map(|&filename| -> Option< |
|
385 | .flat_map(|&filename| -> Option<_> { | |
376 | // TODO normalization |
|
386 | // TODO normalization | |
377 | let normalized = filename; |
|
387 | let normalized = filename; | |
378 |
|
388 | |||
379 | let buf = match hg_path_to_path_buf(normalized) { |
|
389 | let buf = match hg_path_to_path_buf(normalized) { | |
380 | Ok(x) => x, |
|
390 | Ok(x) => x, | |
381 |
Err( |
|
391 | Err(_) => { | |
|
392 | return Some(( | |||
|
393 | Cow::Borrowed(normalized), | |||
|
394 | INVALID_PATH_DISPATCH, | |||
|
395 | )) | |||
|
396 | } | |||
382 | }; |
|
397 | }; | |
383 | let target = self.root_dir.join(buf); |
|
398 | let target = self.root_dir.join(buf); | |
384 | let st = target.symlink_metadata(); |
|
399 | let st = target.symlink_metadata(); | |
@@ -389,7 +404,7 b' where' | |||||
389 | return if file_type.is_file() || file_type.is_symlink() |
|
404 | return if file_type.is_file() || file_type.is_symlink() | |
390 | { |
|
405 | { | |
391 | if let Some(entry) = in_dmap { |
|
406 | if let Some(entry) = in_dmap { | |
392 |
return Some( |
|
407 | return Some(( | |
393 | Cow::Borrowed(normalized), |
|
408 | Cow::Borrowed(normalized), | |
394 | dispatch_found( |
|
409 | dispatch_found( | |
395 | &normalized, |
|
410 | &normalized, | |
@@ -398,26 +413,26 b' where' | |||||
398 | &self.dmap.copy_map, |
|
413 | &self.dmap.copy_map, | |
399 | self.options, |
|
414 | self.options, | |
400 | ), |
|
415 | ), | |
401 |
)) |
|
416 | )); | |
402 | } |
|
417 | } | |
403 |
Some( |
|
418 | Some(( | |
404 | Cow::Borrowed(normalized), |
|
419 | Cow::Borrowed(normalized), | |
405 | Dispatch::Unknown, |
|
420 | Dispatch::Unknown, | |
406 |
)) |
|
421 | )) | |
407 | } else if file_type.is_dir() { |
|
422 | } else if file_type.is_dir() { | |
408 | if self.options.collect_traversed_dirs { |
|
423 | if self.options.collect_traversed_dirs { | |
409 | traversed_sender |
|
424 | traversed_sender | |
410 | .send(normalized.to_owned()) |
|
425 | .send(normalized.to_owned()) | |
411 | .expect("receiver should outlive sender"); |
|
426 | .expect("receiver should outlive sender"); | |
412 | } |
|
427 | } | |
413 |
Some( |
|
428 | Some(( | |
414 | Cow::Borrowed(normalized), |
|
429 | Cow::Borrowed(normalized), | |
415 | Dispatch::Directory { |
|
430 | Dispatch::Directory { | |
416 | was_file: in_dmap.is_some(), |
|
431 | was_file: in_dmap.is_some(), | |
417 | }, |
|
432 | }, | |
418 |
)) |
|
433 | )) | |
419 | } else { |
|
434 | } else { | |
420 |
Some( |
|
435 | Some(( | |
421 | Cow::Borrowed(normalized), |
|
436 | Cow::Borrowed(normalized), | |
422 | Dispatch::Bad(BadMatch::BadType( |
|
437 | Dispatch::Bad(BadMatch::BadType( | |
423 | // TODO do more than unknown |
|
438 | // TODO do more than unknown | |
@@ -428,22 +443,20 b' where' | |||||
428 | // users. |
|
443 | // users. | |
429 | BadType::Unknown, |
|
444 | BadType::Unknown, | |
430 | )), |
|
445 | )), | |
431 |
)) |
|
446 | )) | |
432 | }; |
|
447 | }; | |
433 | } |
|
448 | } | |
434 | Err(_) => { |
|
449 | Err(_) => { | |
435 | if let Some(entry) = in_dmap { |
|
450 | if let Some(entry) = in_dmap { | |
436 |
return Some( |
|
451 | return Some(( | |
437 | Cow::Borrowed(normalized), |
|
452 | Cow::Borrowed(normalized), | |
438 | dispatch_missing(entry.state), |
|
453 | dispatch_missing(entry.state), | |
439 |
)) |
|
454 | )); | |
440 | } |
|
455 | } | |
441 | } |
|
456 | } | |
442 | }; |
|
457 | }; | |
443 | None |
|
458 | None | |
444 | }) |
|
459 | }) | |
445 | .flatten() |
|
|||
446 | .filter_map(Result::ok) |
|
|||
447 | .partition(|(_, dispatch)| match dispatch { |
|
460 | .partition(|(_, dispatch)| match dispatch { | |
448 | Dispatch::Directory { .. } => true, |
|
461 | Dispatch::Directory { .. } => true, | |
449 | _ => false, |
|
462 | _ => false, | |
@@ -462,7 +475,7 b' where' | |||||
462 | old_results: &FastHashMap<HgPathCow<'a>, Dispatch>, |
|
475 | old_results: &FastHashMap<HgPathCow<'a>, Dispatch>, | |
463 | results: &mut Vec<DispatchedPath<'a>>, |
|
476 | results: &mut Vec<DispatchedPath<'a>>, | |
464 | traversed_sender: crossbeam::Sender<HgPathBuf>, |
|
477 | traversed_sender: crossbeam::Sender<HgPathBuf>, | |
465 | ) -> IoResult<()> { |
|
478 | ) { | |
466 | // The traversal is done in parallel, so use a channel to gather |
|
479 | // The traversal is done in parallel, so use a channel to gather | |
467 | // entries. `crossbeam::Sender` is `Sync`, while `mpsc::Sender` |
|
480 | // entries. `crossbeam::Sender` is `Sync`, while `mpsc::Sender` | |
468 | // is not. |
|
481 | // is not. | |
@@ -474,25 +487,17 b' where' | |||||
474 | path, |
|
487 | path, | |
475 | &old_results, |
|
488 | &old_results, | |
476 | traversed_sender, |
|
489 | traversed_sender, | |
477 |
) |
|
490 | ); | |
478 |
|
491 | |||
479 | // Disconnect the channel so the receiver stops waiting |
|
492 | // Disconnect the channel so the receiver stops waiting | |
480 | drop(files_transmitter); |
|
493 | drop(files_transmitter); | |
481 |
|
494 | |||
482 | // TODO don't collect. Find a way of replicating the behavior of |
|
495 | let new_results = files_receiver | |
483 | // `itertools::process_results`, but for `rayon::ParallelIterator` |
|
496 | .into_iter() | |
484 | let new_results: IoResult<Vec<(Cow<HgPath>, Dispatch)>> = |
|
497 | .par_bridge() | |
485 | files_receiver |
|
498 | .map(|(f, d)| (Cow::Owned(f), d)); | |
486 | .into_iter() |
|
|||
487 | .map(|item| { |
|
|||
488 | let (f, d) = item?; |
|
|||
489 | Ok((Cow::Owned(f), d)) |
|
|||
490 | }) |
|
|||
491 | .collect(); |
|
|||
492 |
|
499 | |||
493 |
results.par_extend(new_results |
|
500 | results.par_extend(new_results); | |
494 |
|
||||
495 | Ok(()) |
|
|||
496 | } |
|
501 | } | |
497 |
|
502 | |||
498 | /// Dispatch a single entry (file, folder, symlink...) found during |
|
503 | /// Dispatch a single entry (file, folder, symlink...) found during | |
@@ -501,7 +506,7 b' where' | |||||
501 | fn handle_traversed_entry<'b>( |
|
506 | fn handle_traversed_entry<'b>( | |
502 | &'a self, |
|
507 | &'a self, | |
503 | scope: &rayon::Scope<'b>, |
|
508 | scope: &rayon::Scope<'b>, | |
504 |
files_sender: &'b crossbeam::Sender< |
|
509 | files_sender: &'b crossbeam::Sender<(HgPathBuf, Dispatch)>, | |
505 | old_results: &'a FastHashMap<Cow<HgPath>, Dispatch>, |
|
510 | old_results: &'a FastHashMap<Cow<HgPath>, Dispatch>, | |
506 | filename: HgPathBuf, |
|
511 | filename: HgPathBuf, | |
507 | dir_entry: DirEntry, |
|
512 | dir_entry: DirEntry, | |
@@ -534,7 +539,7 b' where' | |||||
534 | { |
|
539 | { | |
535 | let metadata = dir_entry.metadata()?; |
|
540 | let metadata = dir_entry.metadata()?; | |
536 | files_sender |
|
541 | files_sender | |
537 |
.send( |
|
542 | .send(( | |
538 | filename.to_owned(), |
|
543 | filename.to_owned(), | |
539 | dispatch_found( |
|
544 | dispatch_found( | |
540 | &filename, |
|
545 | &filename, | |
@@ -543,7 +548,7 b' where' | |||||
543 | &self.dmap.copy_map, |
|
548 | &self.dmap.copy_map, | |
544 | self.options, |
|
549 | self.options, | |
545 | ), |
|
550 | ), | |
546 |
)) |
|
551 | )) | |
547 | .unwrap(); |
|
552 | .unwrap(); | |
548 | } |
|
553 | } | |
549 | } else if (self.matcher.matches_everything() |
|
554 | } else if (self.matcher.matches_everything() | |
@@ -556,17 +561,17 b' where' | |||||
556 | { |
|
561 | { | |
557 | if self.options.list_ignored { |
|
562 | if self.options.list_ignored { | |
558 | files_sender |
|
563 | files_sender | |
559 |
.send |
|
564 | .send((filename.to_owned(), Dispatch::Ignored)) | |
560 | .unwrap(); |
|
565 | .unwrap(); | |
561 | } |
|
566 | } | |
562 | } else if self.options.list_unknown { |
|
567 | } else if self.options.list_unknown { | |
563 | files_sender |
|
568 | files_sender | |
564 |
.send |
|
569 | .send((filename.to_owned(), Dispatch::Unknown)) | |
565 | .unwrap(); |
|
570 | .unwrap(); | |
566 | } |
|
571 | } | |
567 | } else if self.is_ignored(&filename) && self.options.list_ignored { |
|
572 | } else if self.is_ignored(&filename) && self.options.list_ignored { | |
568 | files_sender |
|
573 | files_sender | |
569 |
.send |
|
574 | .send((filename.to_owned(), Dispatch::Ignored)) | |
570 | .unwrap(); |
|
575 | .unwrap(); | |
571 | } |
|
576 | } | |
572 | } else if let Some(entry) = entry_option { |
|
577 | } else if let Some(entry) = entry_option { | |
@@ -575,10 +580,7 b' where' | |||||
575 | || self.matcher.matches(&filename) |
|
580 | || self.matcher.matches(&filename) | |
576 | { |
|
581 | { | |
577 | files_sender |
|
582 | files_sender | |
578 | .send(Ok(( |
|
583 | .send((filename.to_owned(), dispatch_missing(entry.state))) | |
579 | filename.to_owned(), |
|
|||
580 | dispatch_missing(entry.state), |
|
|||
581 | ))) |
|
|||
582 | .unwrap(); |
|
584 | .unwrap(); | |
583 | } |
|
585 | } | |
584 | } |
|
586 | } | |
@@ -590,7 +592,7 b' where' | |||||
590 | fn handle_traversed_dir<'b>( |
|
592 | fn handle_traversed_dir<'b>( | |
591 | &'a self, |
|
593 | &'a self, | |
592 | scope: &rayon::Scope<'b>, |
|
594 | scope: &rayon::Scope<'b>, | |
593 |
files_sender: &'b crossbeam::Sender< |
|
595 | files_sender: &'b crossbeam::Sender<(HgPathBuf, Dispatch)>, | |
594 | old_results: &'a FastHashMap<Cow<HgPath>, Dispatch>, |
|
596 | old_results: &'a FastHashMap<Cow<HgPath>, Dispatch>, | |
595 | entry_option: Option<&'a DirstateEntry>, |
|
597 | entry_option: Option<&'a DirstateEntry>, | |
596 | directory: HgPathBuf, |
|
598 | directory: HgPathBuf, | |
@@ -606,10 +608,10 b' where' | |||||
606 | || self.matcher.matches(&directory) |
|
608 | || self.matcher.matches(&directory) | |
607 | { |
|
609 | { | |
608 | files_sender |
|
610 | files_sender | |
609 |
.send( |
|
611 | .send(( | |
610 | directory.to_owned(), |
|
612 | directory.to_owned(), | |
611 | dispatch_missing(entry.state), |
|
613 | dispatch_missing(entry.state), | |
612 |
)) |
|
614 | )) | |
613 | .unwrap(); |
|
615 | .unwrap(); | |
614 | } |
|
616 | } | |
615 | } |
|
617 | } | |
@@ -621,7 +623,6 b' where' | |||||
621 | &old_results, |
|
623 | &old_results, | |
622 | traversed_sender, |
|
624 | traversed_sender, | |
623 | ) |
|
625 | ) | |
624 | .unwrap_or_else(|e| files_sender.send(Err(e)).unwrap()) |
|
|||
625 | } |
|
626 | } | |
626 | }); |
|
627 | }); | |
627 | } |
|
628 | } | |
@@ -630,11 +631,11 b' where' | |||||
630 | /// entries in a separate thread. |
|
631 | /// entries in a separate thread. | |
631 | fn traverse_dir( |
|
632 | fn traverse_dir( | |
632 | &self, |
|
633 | &self, | |
633 |
files_sender: &crossbeam::Sender< |
|
634 | files_sender: &crossbeam::Sender<(HgPathBuf, Dispatch)>, | |
634 | directory: impl AsRef<HgPath>, |
|
635 | directory: impl AsRef<HgPath>, | |
635 | old_results: &FastHashMap<Cow<HgPath>, Dispatch>, |
|
636 | old_results: &FastHashMap<Cow<HgPath>, Dispatch>, | |
636 | traversed_sender: crossbeam::Sender<HgPathBuf>, |
|
637 | traversed_sender: crossbeam::Sender<HgPathBuf>, | |
637 | ) -> IoResult<()> { |
|
638 | ) { | |
638 | let directory = directory.as_ref(); |
|
639 | let directory = directory.as_ref(); | |
639 |
|
640 | |||
640 | if self.options.collect_traversed_dirs { |
|
641 | if self.options.collect_traversed_dirs { | |
@@ -644,38 +645,33 b' where' | |||||
644 | } |
|
645 | } | |
645 |
|
646 | |||
646 | let visit_entries = match self.matcher.visit_children_set(directory) { |
|
647 | let visit_entries = match self.matcher.visit_children_set(directory) { | |
647 |
VisitChildrenSet::Empty => return |
|
648 | VisitChildrenSet::Empty => return, | |
648 | VisitChildrenSet::This | VisitChildrenSet::Recursive => None, |
|
649 | VisitChildrenSet::This | VisitChildrenSet::Recursive => None, | |
649 | VisitChildrenSet::Set(set) => Some(set), |
|
650 | VisitChildrenSet::Set(set) => Some(set), | |
650 | }; |
|
651 | }; | |
651 |
let buf = hg_path_to_path_buf(directory) |
|
652 | let buf = match hg_path_to_path_buf(directory) { | |
|
653 | Ok(b) => b, | |||
|
654 | Err(_) => { | |||
|
655 | files_sender | |||
|
656 | .send((directory.to_owned(), INVALID_PATH_DISPATCH)) | |||
|
657 | .expect("receiver should outlive sender"); | |||
|
658 | return; | |||
|
659 | } | |||
|
660 | }; | |||
652 | let dir_path = self.root_dir.join(buf); |
|
661 | let dir_path = self.root_dir.join(buf); | |
653 |
|
662 | |||
654 | let skip_dot_hg = !directory.as_bytes().is_empty(); |
|
663 | let skip_dot_hg = !directory.as_bytes().is_empty(); | |
655 | let entries = match list_directory(dir_path, skip_dot_hg) { |
|
664 | let entries = match list_directory(dir_path, skip_dot_hg) { | |
656 | Err(e) => { |
|
665 | Err(e) => { | |
657 | return match e.kind() { |
|
666 | files_sender | |
658 | ErrorKind::NotFound | ErrorKind::PermissionDenied => { |
|
667 | .send((directory.to_owned(), dispatch_os_error(&e))) | |
659 | files_sender |
|
668 | .expect("receiver should outlive sender"); | |
660 | .send(Ok(( |
|
669 | return; | |
661 | directory.to_owned(), |
|
|||
662 | Dispatch::Bad(BadMatch::OsError( |
|
|||
663 | // Unwrapping here is OK because the error |
|
|||
664 | // always is a |
|
|||
665 | // real os error |
|
|||
666 | e.raw_os_error().unwrap(), |
|
|||
667 | )), |
|
|||
668 | ))) |
|
|||
669 | .expect("receiver should outlive sender"); |
|
|||
670 | Ok(()) |
|
|||
671 | } |
|
|||
672 | _ => Err(e), |
|
|||
673 | }; |
|
|||
674 | } |
|
670 | } | |
675 | Ok(entries) => entries, |
|
671 | Ok(entries) => entries, | |
676 | }; |
|
672 | }; | |
677 |
|
673 | |||
678 |
rayon::scope(|scope| |
|
674 | rayon::scope(|scope| { | |
679 | for (filename, dir_entry) in entries { |
|
675 | for (filename, dir_entry) in entries { | |
680 | if let Some(ref set) = visit_entries { |
|
676 | if let Some(ref set) = visit_entries { | |
681 | if !set.contains(filename.deref()) { |
|
677 | if !set.contains(filename.deref()) { | |
@@ -690,17 +686,26 b' where' | |||||
690 | }; |
|
686 | }; | |
691 |
|
687 | |||
692 | if !old_results.contains_key(filename.deref()) { |
|
688 | if !old_results.contains_key(filename.deref()) { | |
693 | self.handle_traversed_entry( |
|
689 | match self.handle_traversed_entry( | |
694 | scope, |
|
690 | scope, | |
695 | files_sender, |
|
691 | files_sender, | |
696 | old_results, |
|
692 | old_results, | |
697 | filename, |
|
693 | filename, | |
698 | dir_entry, |
|
694 | dir_entry, | |
699 | traversed_sender.clone(), |
|
695 | traversed_sender.clone(), | |
700 |
) |
|
696 | ) { | |
|
697 | Err(e) => { | |||
|
698 | files_sender | |||
|
699 | .send(( | |||
|
700 | directory.to_owned(), | |||
|
701 | dispatch_os_error(&e), | |||
|
702 | )) | |||
|
703 | .expect("receiver should outlive sender"); | |||
|
704 | } | |||
|
705 | Ok(_) => {} | |||
|
706 | } | |||
701 | } |
|
707 | } | |
702 | } |
|
708 | } | |
703 | Ok(()) |
|
|||
704 | }) |
|
709 | }) | |
705 | } |
|
710 | } | |
706 |
|
711 | |||
@@ -716,14 +721,23 b' where' | |||||
716 | .fs_iter(self.root_dir.clone()) |
|
721 | .fs_iter(self.root_dir.clone()) | |
717 | .par_bridge() |
|
722 | .par_bridge() | |
718 | .filter(|(path, _)| self.matcher.matches(path)) |
|
723 | .filter(|(path, _)| self.matcher.matches(path)) | |
719 |
. |
|
724 | .map(move |(filename, shortcut)| { | |
720 | let entry = match shortcut { |
|
725 | let entry = match shortcut { | |
721 | StatusShortcut::Entry(e) => e, |
|
726 | StatusShortcut::Entry(e) => e, | |
722 | StatusShortcut::Dispatch(d) => { |
|
727 | StatusShortcut::Dispatch(d) => { | |
723 |
return |
|
728 | return (Cow::Owned(filename), d) | |
724 | } |
|
729 | } | |
725 | }; |
|
730 | }; | |
726 |
let filename_as_path = hg_path_to_path_buf(&filename) |
|
731 | let filename_as_path = match hg_path_to_path_buf(&filename) | |
|
732 | { | |||
|
733 | Ok(f) => f, | |||
|
734 | Err(_) => { | |||
|
735 | return ( | |||
|
736 | Cow::Owned(filename), | |||
|
737 | INVALID_PATH_DISPATCH, | |||
|
738 | ) | |||
|
739 | } | |||
|
740 | }; | |||
727 | let meta = self |
|
741 | let meta = self | |
728 | .root_dir |
|
742 | .root_dir | |
729 | .join(filename_as_path) |
|
743 | .join(filename_as_path) | |
@@ -734,10 +748,10 b' where' | |||||
734 | if !(m.file_type().is_file() |
|
748 | if !(m.file_type().is_file() | |
735 | || m.file_type().is_symlink()) => |
|
749 | || m.file_type().is_symlink()) => | |
736 | { |
|
750 | { | |
737 |
|
|
751 | ( | |
738 | Cow::Owned(filename), |
|
752 | Cow::Owned(filename), | |
739 | dispatch_missing(entry.state), |
|
753 | dispatch_missing(entry.state), | |
740 |
) |
|
754 | ) | |
741 | } |
|
755 | } | |
742 | Ok(m) => { |
|
756 | Ok(m) => { | |
743 | let dispatch = dispatch_found( |
|
757 | let dispatch = dispatch_found( | |
@@ -747,7 +761,7 b' where' | |||||
747 | &self.dmap.copy_map, |
|
761 | &self.dmap.copy_map, | |
748 | self.options, |
|
762 | self.options, | |
749 | ); |
|
763 | ); | |
750 |
|
|
764 | (Cow::Owned(filename), dispatch) | |
751 | } |
|
765 | } | |
752 | Err(e) |
|
766 | Err(e) | |
753 | if e.kind() == ErrorKind::NotFound |
|
767 | if e.kind() == ErrorKind::NotFound | |
@@ -758,12 +772,14 b' where' | |||||
758 | // It happens if the dirstate contains `foo/bar` |
|
772 | // It happens if the dirstate contains `foo/bar` | |
759 | // and foo is not a |
|
773 | // and foo is not a | |
760 | // directory |
|
774 | // directory | |
761 |
|
|
775 | ( | |
762 | Cow::Owned(filename), |
|
776 | Cow::Owned(filename), | |
763 | dispatch_missing(entry.state), |
|
777 | dispatch_missing(entry.state), | |
764 |
) |
|
778 | ) | |
765 | } |
|
779 | } | |
766 |
Err(e) => |
|
780 | Err(e) => { | |
|
781 | (Cow::Owned(filename), dispatch_os_error(&e)) | |||
|
782 | } | |||
767 | } |
|
783 | } | |
768 | }), |
|
784 | }), | |
769 | ); |
|
785 | ); | |
@@ -776,10 +792,18 b' where' | |||||
776 | #[cfg(not(feature = "dirstate-tree"))] |
|
792 | #[cfg(not(feature = "dirstate-tree"))] | |
777 | #[timed] |
|
793 | #[timed] | |
778 | pub fn extend_from_dmap(&self, results: &mut Vec<DispatchedPath<'a>>) { |
|
794 | pub fn extend_from_dmap(&self, results: &mut Vec<DispatchedPath<'a>>) { | |
779 |
results.par_extend(self.dmap.par_iter(). |
|
795 | results.par_extend(self.dmap.par_iter().map( | |
780 | move |(filename, entry)| { |
|
796 | move |(filename, entry)| { | |
781 | let filename: &HgPath = filename; |
|
797 | let filename: &HgPath = filename; | |
782 |
let filename_as_path = hg_path_to_path_buf(filename) |
|
798 | let filename_as_path = match hg_path_to_path_buf(filename) { | |
|
799 | Ok(f) => f, | |||
|
800 | Err(_) => { | |||
|
801 | return ( | |||
|
802 | Cow::Borrowed(filename), | |||
|
803 | INVALID_PATH_DISPATCH, | |||
|
804 | ) | |||
|
805 | } | |||
|
806 | }; | |||
783 | let meta = |
|
807 | let meta = | |
784 | self.root_dir.join(filename_as_path).symlink_metadata(); |
|
808 | self.root_dir.join(filename_as_path).symlink_metadata(); | |
785 | match meta { |
|
809 | match meta { | |
@@ -787,12 +811,12 b' where' | |||||
787 | if !(m.file_type().is_file() |
|
811 | if !(m.file_type().is_file() | |
788 | || m.file_type().is_symlink()) => |
|
812 | || m.file_type().is_symlink()) => | |
789 | { |
|
813 | { | |
790 |
|
|
814 | ( | |
791 | Cow::Borrowed(filename), |
|
815 | Cow::Borrowed(filename), | |
792 | dispatch_missing(entry.state), |
|
816 | dispatch_missing(entry.state), | |
793 |
) |
|
817 | ) | |
794 | } |
|
818 | } | |
795 |
Ok(m) => |
|
819 | Ok(m) => ( | |
796 | Cow::Borrowed(filename), |
|
820 | Cow::Borrowed(filename), | |
797 | dispatch_found( |
|
821 | dispatch_found( | |
798 | filename, |
|
822 | filename, | |
@@ -801,7 +825,7 b' where' | |||||
801 | &self.dmap.copy_map, |
|
825 | &self.dmap.copy_map, | |
802 | self.options, |
|
826 | self.options, | |
803 | ), |
|
827 | ), | |
804 |
) |
|
828 | ), | |
805 | Err(e) |
|
829 | Err(e) | |
806 | if e.kind() == ErrorKind::NotFound |
|
830 | if e.kind() == ErrorKind::NotFound | |
807 | || e.raw_os_error() == Some(20) => |
|
831 | || e.raw_os_error() == Some(20) => | |
@@ -811,12 +835,12 b' where' | |||||
811 | // It happens if the dirstate contains `foo/bar` |
|
835 | // It happens if the dirstate contains `foo/bar` | |
812 | // and foo is not a |
|
836 | // and foo is not a | |
813 | // directory |
|
837 | // directory | |
814 |
|
|
838 | ( | |
815 | Cow::Borrowed(filename), |
|
839 | Cow::Borrowed(filename), | |
816 | dispatch_missing(entry.state), |
|
840 | dispatch_missing(entry.state), | |
817 |
) |
|
841 | ) | |
818 | } |
|
842 | } | |
819 |
Err(e) => |
|
843 | Err(e) => (Cow::Borrowed(filename), dispatch_os_error(&e)), | |
820 | } |
|
844 | } | |
821 | }, |
|
845 | }, | |
822 | )); |
|
846 | )); | |
@@ -830,10 +854,7 b' where' | |||||
830 | /// `extend` in timings |
|
854 | /// `extend` in timings | |
831 | #[cfg(not(feature = "dirstate-tree"))] |
|
855 | #[cfg(not(feature = "dirstate-tree"))] | |
832 | #[timed] |
|
856 | #[timed] | |
833 | pub fn handle_unknowns( |
|
857 | pub fn handle_unknowns(&self, results: &mut Vec<DispatchedPath<'a>>) { | |
834 | &self, |
|
|||
835 | results: &mut Vec<DispatchedPath<'a>>, |
|
|||
836 | ) -> IoResult<()> { |
|
|||
837 | let to_visit: Vec<(&HgPath, &DirstateEntry)> = |
|
858 | let to_visit: Vec<(&HgPath, &DirstateEntry)> = | |
838 | if results.is_empty() && self.matcher.matches_everything() { |
|
859 | if results.is_empty() && self.matcher.matches_everything() { | |
839 | self.dmap.iter().map(|(f, e)| (f.deref(), e)).collect() |
|
860 | self.dmap.iter().map(|(f, e)| (f.deref(), e)).collect() | |
@@ -857,21 +878,23 b' where' | |||||
857 |
|
878 | |||
858 | let path_auditor = PathAuditor::new(&self.root_dir); |
|
879 | let path_auditor = PathAuditor::new(&self.root_dir); | |
859 |
|
880 | |||
860 | // TODO don't collect. Find a way of replicating the behavior of |
|
881 | let new_results = to_visit.into_par_iter().filter_map( | |
861 | // `itertools::process_results`, but for `rayon::ParallelIterator` |
|
882 | |(filename, entry)| -> Option<_> { | |
862 | let new_results: IoResult<Vec<_>> = to_visit |
|
|||
863 | .into_par_iter() |
|
|||
864 | .filter_map(|(filename, entry)| -> Option<IoResult<_>> { |
|
|||
865 | // Report ignored items in the dmap as long as they are not |
|
883 | // Report ignored items in the dmap as long as they are not | |
866 | // under a symlink directory. |
|
884 | // under a symlink directory. | |
867 | if path_auditor.check(filename) { |
|
885 | if path_auditor.check(filename) { | |
868 | // TODO normalize for case-insensitive filesystems |
|
886 | // TODO normalize for case-insensitive filesystems | |
869 | let buf = match hg_path_to_path_buf(filename) { |
|
887 | let buf = match hg_path_to_path_buf(filename) { | |
870 | Ok(x) => x, |
|
888 | Ok(x) => x, | |
871 |
Err( |
|
889 | Err(_) => { | |
|
890 | return Some(( | |||
|
891 | Cow::Owned(filename.to_owned()), | |||
|
892 | INVALID_PATH_DISPATCH, | |||
|
893 | )); | |||
|
894 | } | |||
872 | }; |
|
895 | }; | |
873 |
Some( |
|
896 | Some(( | |
874 |
Cow:: |
|
897 | Cow::Owned(filename.to_owned()), | |
875 | match self.root_dir.join(&buf).symlink_metadata() { |
|
898 | match self.root_dir.join(&buf).symlink_metadata() { | |
876 | // File was just ignored, no links, and exists |
|
899 | // File was just ignored, no links, and exists | |
877 | Ok(meta) => { |
|
900 | Ok(meta) => { | |
@@ -887,21 +910,19 b' where' | |||||
887 | // File doesn't exist |
|
910 | // File doesn't exist | |
888 | Err(_) => dispatch_missing(entry.state), |
|
911 | Err(_) => dispatch_missing(entry.state), | |
889 | }, |
|
912 | }, | |
890 |
)) |
|
913 | )) | |
891 | } else { |
|
914 | } else { | |
892 | // It's either missing or under a symlink directory which |
|
915 | // It's either missing or under a symlink directory which | |
893 | // we, in this case, report as missing. |
|
916 | // we, in this case, report as missing. | |
894 |
Some( |
|
917 | Some(( | |
895 |
Cow:: |
|
918 | Cow::Owned(filename.to_owned()), | |
896 | dispatch_missing(entry.state), |
|
919 | dispatch_missing(entry.state), | |
897 |
)) |
|
920 | )) | |
898 | } |
|
921 | } | |
899 |
} |
|
922 | }, | |
900 |
|
|
923 | ); | |
901 |
|
924 | |||
902 |
results.par_extend(new_results |
|
925 | results.par_extend(new_results); | |
903 |
|
||||
904 | Ok(()) |
|
|||
905 | } |
|
926 | } | |
906 | } |
|
927 | } | |
907 |
|
928 |
@@ -56,7 +56,7 b" impl<'a, M: Matcher + Sync> Status<'a, M" | |||||
56 | .expect("old results should exist"), |
|
56 | .expect("old results should exist"), | |
57 | &mut results, |
|
57 | &mut results, | |
58 | traversed_sender.clone(), |
|
58 | traversed_sender.clone(), | |
59 |
) |
|
59 | ); | |
60 | } |
|
60 | } | |
61 | } |
|
61 | } | |
62 | _ => { |
|
62 | _ => { | |
@@ -104,7 +104,7 b" impl<'a, M: Matcher + Sync> Status<'a, M" | |||||
104 | &old_results, |
|
104 | &old_results, | |
105 | &mut results, |
|
105 | &mut results, | |
106 | traversed_sender.clone(), |
|
106 | traversed_sender.clone(), | |
107 |
) |
|
107 | ); | |
108 | } |
|
108 | } | |
109 | } |
|
109 | } | |
110 | _ => { |
|
110 | _ => { | |
@@ -116,7 +116,7 b" impl<'a, M: Matcher + Sync> Status<'a, M" | |||||
116 |
|
116 | |||
117 | if !self.matcher.is_exact() { |
|
117 | if !self.matcher.is_exact() { | |
118 | if self.options.list_unknown { |
|
118 | if self.options.list_unknown { | |
119 |
self.handle_unknowns(&mut results) |
|
119 | self.handle_unknowns(&mut results); | |
120 | } else { |
|
120 | } else { | |
121 | // TODO this is incorrect, see issue6335 |
|
121 | // TODO this is incorrect, see issue6335 | |
122 | // This requires a fix in both Python and Rust that can happen |
|
122 | // This requires a fix in both Python and Rust that can happen |
General Comments 0
You need to be logged in to leave comments.
Login now