History

port PathCache over to `Stack` (#301)

Tests for PathCache still work, which means that a lot of logic should be usable right away for implementing ignore paths.

Sebastian Thiel committed 4 years ago

Commit ebfea8d1 parent 0d3ba1a2 files · +21 −67Browse files

Unified · Split

2 files
  1. git-worktree/src/fs.rs +1 −1
  2. git-worktree/src/index/checkout.rs +20 −66
git-worktree/src/fs.rs+1−1
@@ -189,7 +189,7 @@ pub mod stack { · 188 unmodified lines
189189 /// along with the stacks state for inspection to perform an operation that produces some data.
190190 ///
191191 /// The full path to `relative` will be returned along with the data returned by push_comp.
192− pub fn make_relative_path_current<F>(
192+ pub fn make_relative_path_current(
193193 &mut self,
194194 relative: impl AsRef<Path>,
195195 mut push_comp: impl FnMut(&mut std::iter::Peekable<std::path::Components<'_>>, &Self) -> std::io::Result<T>,
git-worktree/src/index/checkout.rs+20−66
@@ -1,5 +1,4 @@
1−use std::path::PathBuf;
2−
1+use crate::fs;
32 use bstr::BString;
43
54 /// A cache for directory creation to reduce the amount of stat calls when creating
@@ -18,15 +17,7 @@ use bstr::BString; · 12 unmodified lines
1817 /// The caching is only useful if consecutive calls to create a directory are using a sorted list of entries.
1918 #[allow(unused)]
2019 pub struct PathCache {
21− /// The prefix/root for all paths we handle.
22− root: PathBuf,
23− /// the most recent known cached that we know is valid.
24− valid: PathBuf,
25− /// The relative portion of `valid` that was added previously.
26− valid_relative: PathBuf,
27− /// The amount of path components of 'valid' beyond the roots components. If `root` has 2, and this is 2, `valid` has 4 components.
28− valid_components: usize,
29−
20+ stack: fs::Stack<()>,
3021 /// If there is a symlink or a file in our path, try to unlink it before creating the directory.
3122 pub unlink_on_collision: bool,
3223
@@ -39,7 +30,7 @@ mod cache { · 6 unmodified lines
3930 use std::path::{Path, PathBuf};
4031
4132 use super::PathCache;
42− use crate::os;
33+ use crate::{fs, os};
4334
4435 impl PathCache {
4536 /// Create a new instance with `root` being the base for all future paths we handle, assuming it to be valid which includes
@@ -47,10 +38,7 @@ mod cache { · 1 unmodified line
4738 pub fn new(root: impl Into<PathBuf>) -> Self {
4839 let root = root.into();
4940 PathCache {
50− valid: root.clone(),
51− valid_relative: PathBuf::with_capacity(128),
52− valid_components: 0,
53− root,
41+ stack: fs::Stack::new(root),
5442 #[cfg(debug_assertions)]
5543 test_mkdir_calls: 0,
5644 unlink_on_collision: false,
@@ -66,58 +54,33 @@ mod cache { · 9 unmodified lines
6654 relative: impl AsRef<Path>,
6755 mode: git_index::entry::Mode,
6856 ) -> std::io::Result<&Path> {
69− let relative = relative.as_ref();
70− debug_assert!(
71− relative.is_relative(),
72− "only index paths are handled correctly here, must be relative"
73− );
74−
75− let mut components = relative.components().peekable();
76− let mut existing_components = self.valid_relative.components();
77− let mut matching_components = 0;
78− while let (Some(existing_comp), Some(new_comp)) = (existing_components.next(), components.peek()) {
79− if existing_comp == *new_comp {
80− components.next();
81− matching_components += 1;
82− } else {
83− break;
84− }
85− }
86−
87− for _ in 0..self.valid_components - matching_components {
88− self.valid.pop();
89− self.valid_relative.pop();
90− }
91−
92− self.valid_components = matching_components;
93−
94− let target_is_dir = mode == git_index::entry::Mode::COMMIT || mode == git_index::entry::Mode::DIR;
95− while let Some(comp) = components.next() {
96− self.valid.push(comp);
97− self.valid_relative.push(comp);
98− self.valid_components += 1;
99− let res = (|| {
57+ #[cfg(debug_assertions)]
58+ let mkdir_calls = &mut self.test_mkdir_calls;
59+ let unlink_on_collision = self.unlink_on_collision;
60+ self.stack
61+ .make_relative_path_current(relative, |components, stack: &fs::Stack<()>| {
62+ let target_is_dir = mode == git_index::entry::Mode::COMMIT || mode == git_index::entry::Mode::DIR;
10063 if components.peek().is_some() || target_is_dir {
10164 #[cfg(debug_assertions)]
10265 {
103− self.test_mkdir_calls += 1;
66+ *mkdir_calls += 1;
10467 }
105− match std::fs::create_dir(&self.valid) {
68+ match std::fs::create_dir(stack.current()) {
10669 Ok(()) => {}
10770 Err(err) if err.kind() == std::io::ErrorKind::AlreadyExists => {
108− let meta = self.valid.symlink_metadata()?;
71+ let meta = stack.current().symlink_metadata()?;
10972 if !meta.is_dir() {
110− if self.unlink_on_collision {
73+ if unlink_on_collision {
11174 if meta.is_symlink() {
112− os::remove_symlink(&self.valid)?;
75+ os::remove_symlink(stack.current())?;
11376 } else {
114− std::fs::remove_file(&self.valid)?;
77+ std::fs::remove_file(stack.current())?;
11578 }
11679 #[cfg(debug_assertions)]
11780 {
118− self.test_mkdir_calls += 1;
81+ *mkdir_calls += 1;
11982 }
120− std::fs::create_dir(&self.valid)?;
83+ std::fs::create_dir(stack.current())?;
12184 } else {
12285 return Err(err);
12386 }
@@ -127,17 +90,8 @@ mod cache { · 3 unmodified lines
12790 }
12891 }
12992 Ok(())
130− })();
131−
132− if let Err(err) = res {
133− self.valid.pop();
134− self.valid_relative.pop();
135− self.valid_components -= 1;
136− return Err(err);
137− }
138− }
139−
140− Ok(&self.valid)
93+ })
94+ .map(|(p, _)| p)
14195 }
14296 }
14397 }