Show More
@@ -468,6 +468,7 b' dependencies = [' | |||||
468 | "log", |
|
468 | "log", | |
469 | "memmap2", |
|
469 | "memmap2", | |
470 | "micro-timer", |
|
470 | "micro-timer", | |
|
471 | "once_cell", | |||
471 | "ouroboros", |
|
472 | "ouroboros", | |
472 | "pretty_assertions", |
|
473 | "pretty_assertions", | |
473 | "rand 0.8.5", |
|
474 | "rand 0.8.5", | |
@@ -687,6 +688,12 b' dependencies = [' | |||||
687 | ] |
|
688 | ] | |
688 |
|
689 | |||
689 | [[package]] |
|
690 | [[package]] | |
|
691 | name = "once_cell" | |||
|
692 | version = "1.14.0" | |||
|
693 | source = "registry+https://github.com/rust-lang/crates.io-index" | |||
|
694 | checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" | |||
|
695 | ||||
|
696 | [[package]] | |||
690 | name = "opaque-debug" |
|
697 | name = "opaque-debug" | |
691 | version = "0.3.0" |
|
698 | version = "0.3.0" | |
692 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
699 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -35,6 +35,9 b' log = "0.4.8"' | |||||
35 | memmap2 = { version = "0.5.3", features = ["stable_deref_trait"] } |
|
35 | memmap2 = { version = "0.5.3", features = ["stable_deref_trait"] } | |
36 | zstd = "0.5.3" |
|
36 | zstd = "0.5.3" | |
37 | format-bytes = "0.3.0" |
|
37 | format-bytes = "0.3.0" | |
|
38 | # once_cell 1.15 uses edition 2021, while the heptapod CI | |||
|
39 | # uses an old version of Cargo that doesn't support it. | |||
|
40 | once_cell = "=1.14.0" | |||
38 |
|
41 | |||
39 | # We don't use the `miniz-oxide` backend to not change rhg benchmarks and until |
|
42 | # We don't use the `miniz-oxide` backend to not change rhg benchmarks and until | |
40 | # we have a clearer view of which backend is the fastest. |
|
43 | # we have a clearer view of which backend is the fastest. |
@@ -20,6 +20,7 b' use crate::PatternFileWarning;' | |||||
20 | use crate::StatusError; |
|
20 | use crate::StatusError; | |
21 | use crate::StatusOptions; |
|
21 | use crate::StatusOptions; | |
22 | use micro_timer::timed; |
|
22 | use micro_timer::timed; | |
|
23 | use once_cell::sync::OnceCell; | |||
23 | use rayon::prelude::*; |
|
24 | use rayon::prelude::*; | |
24 | use sha1::{Digest, Sha1}; |
|
25 | use sha1::{Digest, Sha1}; | |
25 | use std::borrow::Cow; |
|
26 | use std::borrow::Cow; | |
@@ -126,14 +127,14 b" pub fn status<'dirstate>(" | |||||
126 | }; |
|
127 | }; | |
127 | let is_at_repo_root = true; |
|
128 | let is_at_repo_root = true; | |
128 | let hg_path = &BorrowedPath::OnDisk(HgPath::new("")); |
|
129 | let hg_path = &BorrowedPath::OnDisk(HgPath::new("")); | |
129 |
let has_ignored_ancestor = |
|
130 | let has_ignored_ancestor = HasIgnoredAncestor::create(None, hg_path); | |
130 | let root_cached_mtime = None; |
|
131 | let root_cached_mtime = None; | |
131 | let root_dir_metadata = None; |
|
132 | let root_dir_metadata = None; | |
132 | // If the path we have for the repository root is a symlink, do follow it. |
|
133 | // If the path we have for the repository root is a symlink, do follow it. | |
133 | // (As opposed to symlinks within the working directory which are not |
|
134 | // (As opposed to symlinks within the working directory which are not | |
134 | // followed, using `std::fs::symlink_metadata`.) |
|
135 | // followed, using `std::fs::symlink_metadata`.) | |
135 | common.traverse_fs_directory_and_dirstate( |
|
136 | common.traverse_fs_directory_and_dirstate( | |
136 | has_ignored_ancestor, |
|
137 | &has_ignored_ancestor, | |
137 | dmap.root.as_ref(), |
|
138 | dmap.root.as_ref(), | |
138 | hg_path, |
|
139 | hg_path, | |
139 | &root_dir, |
|
140 | &root_dir, | |
@@ -196,6 +197,40 b' enum Outcome {' | |||||
196 | Unsure, |
|
197 | Unsure, | |
197 | } |
|
198 | } | |
198 |
|
199 | |||
|
200 | /// Lazy computation of whether a given path has a hgignored | |||
|
201 | /// ancestor. | |||
|
202 | struct HasIgnoredAncestor<'a> { | |||
|
203 | /// `path` and `parent` constitute the inputs to the computation, | |||
|
204 | /// `cache` stores the outcome. | |||
|
205 | path: &'a HgPath, | |||
|
206 | parent: Option<&'a HasIgnoredAncestor<'a>>, | |||
|
207 | cache: OnceCell<bool>, | |||
|
208 | } | |||
|
209 | ||||
|
210 | impl<'a> HasIgnoredAncestor<'a> { | |||
|
211 | fn create( | |||
|
212 | parent: Option<&'a HasIgnoredAncestor<'a>>, | |||
|
213 | path: &'a HgPath, | |||
|
214 | ) -> HasIgnoredAncestor<'a> { | |||
|
215 | Self { | |||
|
216 | path, | |||
|
217 | parent, | |||
|
218 | cache: OnceCell::new(), | |||
|
219 | } | |||
|
220 | } | |||
|
221 | ||||
|
222 | fn force<'b>(&self, ignore_fn: &IgnoreFnType<'b>) -> bool { | |||
|
223 | match self.parent { | |||
|
224 | None => false, | |||
|
225 | Some(parent) => { | |||
|
226 | *(parent.cache.get_or_init(|| { | |||
|
227 | parent.force(ignore_fn) || ignore_fn(&self.path) | |||
|
228 | })) | |||
|
229 | } | |||
|
230 | } | |||
|
231 | } | |||
|
232 | } | |||
|
233 | ||||
199 | impl<'a, 'tree, 'on_disk> StatusCommon<'a, 'tree, 'on_disk> { |
|
234 | impl<'a, 'tree, 'on_disk> StatusCommon<'a, 'tree, 'on_disk> { | |
200 | fn push_outcome( |
|
235 | fn push_outcome( | |
201 | &self, |
|
236 | &self, | |
@@ -318,9 +353,9 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||||
318 |
|
353 | |||
319 | /// Returns whether all child entries of the filesystem directory have a |
|
354 | /// Returns whether all child entries of the filesystem directory have a | |
320 | /// corresponding dirstate node or are ignored. |
|
355 | /// corresponding dirstate node or are ignored. | |
321 | fn traverse_fs_directory_and_dirstate( |
|
356 | fn traverse_fs_directory_and_dirstate<'ancestor>( | |
322 | &self, |
|
357 | &self, | |
323 |
has_ignored_ancestor: |
|
358 | has_ignored_ancestor: &'ancestor HasIgnoredAncestor<'ancestor>, | |
324 | dirstate_nodes: ChildNodesRef<'tree, 'on_disk>, |
|
359 | dirstate_nodes: ChildNodesRef<'tree, 'on_disk>, | |
325 | directory_hg_path: &BorrowedPath<'tree, 'on_disk>, |
|
360 | directory_hg_path: &BorrowedPath<'tree, 'on_disk>, | |
326 | directory_fs_path: &Path, |
|
361 | directory_fs_path: &Path, | |
@@ -418,7 +453,7 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||||
418 | } |
|
453 | } | |
419 | Right(fs_entry) => { |
|
454 | Right(fs_entry) => { | |
420 | has_dirstate_node_or_is_ignored = self.traverse_fs_only( |
|
455 | has_dirstate_node_or_is_ignored = self.traverse_fs_only( | |
421 | has_ignored_ancestor, |
|
456 | has_ignored_ancestor.force(&self.ignore_fn), | |
422 | directory_hg_path, |
|
457 | directory_hg_path, | |
423 | fs_entry, |
|
458 | fs_entry, | |
424 | ) |
|
459 | ) | |
@@ -429,12 +464,12 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||||
429 | .try_reduce(|| true, |a, b| Ok(a && b)) |
|
464 | .try_reduce(|| true, |a, b| Ok(a && b)) | |
430 | } |
|
465 | } | |
431 |
|
466 | |||
432 | fn traverse_fs_and_dirstate( |
|
467 | fn traverse_fs_and_dirstate<'ancestor>( | |
433 | &self, |
|
468 | &self, | |
434 | fs_path: &Path, |
|
469 | fs_path: &Path, | |
435 | fs_metadata: &std::fs::Metadata, |
|
470 | fs_metadata: &std::fs::Metadata, | |
436 | dirstate_node: NodeRef<'tree, 'on_disk>, |
|
471 | dirstate_node: NodeRef<'tree, 'on_disk>, | |
437 |
has_ignored_ancestor: |
|
472 | has_ignored_ancestor: &'ancestor HasIgnoredAncestor<'ancestor>, | |
438 | ) -> Result<(), DirstateV2ParseError> { |
|
473 | ) -> Result<(), DirstateV2ParseError> { | |
439 | self.check_for_outdated_directory_cache(&dirstate_node)?; |
|
474 | self.check_for_outdated_directory_cache(&dirstate_node)?; | |
440 | let hg_path = &dirstate_node.full_path_borrowed(self.dmap.on_disk)?; |
|
475 | let hg_path = &dirstate_node.full_path_borrowed(self.dmap.on_disk)?; | |
@@ -454,11 +489,14 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||||
454 | .traversed |
|
489 | .traversed | |
455 | .push(hg_path.detach_from_tree()) |
|
490 | .push(hg_path.detach_from_tree()) | |
456 | } |
|
491 | } | |
457 |
let is_ignored = |
|
492 | let is_ignored = HasIgnoredAncestor::create( | |
|
493 | Some(&has_ignored_ancestor), | |||
|
494 | hg_path, | |||
|
495 | ); | |||
458 | let is_at_repo_root = false; |
|
496 | let is_at_repo_root = false; | |
459 | let children_all_have_dirstate_node_or_are_ignored = self |
|
497 | let children_all_have_dirstate_node_or_are_ignored = self | |
460 | .traverse_fs_directory_and_dirstate( |
|
498 | .traverse_fs_directory_and_dirstate( | |
461 | is_ignored, |
|
499 | &is_ignored, | |
462 | dirstate_node.children(self.dmap.on_disk)?, |
|
500 | dirstate_node.children(self.dmap.on_disk)?, | |
463 | hg_path, |
|
501 | hg_path, | |
464 | fs_path, |
|
502 | fs_path, | |
@@ -472,14 +510,14 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||||
472 | dirstate_node, |
|
510 | dirstate_node, | |
473 | )? |
|
511 | )? | |
474 | } else { |
|
512 | } else { | |
475 | if file_or_symlink && self.matcher.matches(hg_path) { |
|
513 | if file_or_symlink && self.matcher.matches(&hg_path) { | |
476 | if let Some(entry) = dirstate_node.entry()? { |
|
514 | if let Some(entry) = dirstate_node.entry()? { | |
477 | if !entry.any_tracked() { |
|
515 | if !entry.any_tracked() { | |
478 | // Forward-compat if we start tracking unknown/ignored |
|
516 | // Forward-compat if we start tracking unknown/ignored | |
479 | // files for caching reasons |
|
517 | // files for caching reasons | |
480 | self.mark_unknown_or_ignored( |
|
518 | self.mark_unknown_or_ignored( | |
481 | has_ignored_ancestor, |
|
519 | has_ignored_ancestor.force(&self.ignore_fn), | |
482 | hg_path, |
|
520 | &hg_path, | |
483 | ); |
|
521 | ); | |
484 | } |
|
522 | } | |
485 | if entry.added() { |
|
523 | if entry.added() { | |
@@ -495,7 +533,7 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||||
495 | // `node.entry.is_none()` indicates a "directory" |
|
533 | // `node.entry.is_none()` indicates a "directory" | |
496 | // node, but the filesystem has a file |
|
534 | // node, but the filesystem has a file | |
497 | self.mark_unknown_or_ignored( |
|
535 | self.mark_unknown_or_ignored( | |
498 | has_ignored_ancestor, |
|
536 | has_ignored_ancestor.force(&self.ignore_fn), | |
499 | hg_path, |
|
537 | hg_path, | |
500 | ); |
|
538 | ); | |
501 | } |
|
539 | } |
General Comments 0
You need to be logged in to leave comments.
Login now