Tests for PathCache still work, which means that a lot of logic should be usable right away for implementing ignore paths.
Unified · Split
| @@ -189,7 +189,7 @@ pub mod stack { · 188 unmodified lines | ||
| 189 | 189 | /// along with the stacks state for inspection to perform an operation that produces some data. |
| 190 | 190 | /// |
| 191 | 191 | /// 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( | |
| 193 | 193 | &mut self, |
| 194 | 194 | relative: impl AsRef<Path>, |
| 195 | 195 | mut push_comp: impl FnMut(&mut std::iter::Peekable<std::path::Components<'_>>, &Self) -> std::io::Result<T>, |
| @@ -1,5 +1,4 @@ | ||
| 1 | −use std::path::PathBuf; | |
| 2 | − | |
| 1 | +use crate::fs; | |
| 3 | 2 | use bstr::BString; |
| 4 | 3 | |
| 5 | 4 | /// A cache for directory creation to reduce the amount of stat calls when creating |
| @@ -18,15 +17,7 @@ use bstr::BString; · 12 unmodified lines | ||
| 18 | 17 | /// The caching is only useful if consecutive calls to create a directory are using a sorted list of entries. |
| 19 | 18 | #[allow(unused)] |
| 20 | 19 | 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<()>, | |
| 30 | 21 | /// If there is a symlink or a file in our path, try to unlink it before creating the directory. |
| 31 | 22 | pub unlink_on_collision: bool, |
| 32 | 23 | |
| @@ -39,7 +30,7 @@ mod cache { · 6 unmodified lines | ||
| 39 | 30 | use std::path::{Path, PathBuf}; |
| 40 | 31 | |
| 41 | 32 | use super::PathCache; |
| 42 | − use crate::os; | |
| 33 | + use crate::{fs, os}; | |
| 43 | 34 | |
| 44 | 35 | impl PathCache { |
| 45 | 36 | /// 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 | ||
| 47 | 38 | pub fn new(root: impl Into<PathBuf>) -> Self { |
| 48 | 39 | let root = root.into(); |
| 49 | 40 | PathCache { |
| 50 | − valid: root.clone(), | |
| 51 | − valid_relative: PathBuf::with_capacity(128), | |
| 52 | − valid_components: 0, | |
| 53 | − root, | |
| 41 | + stack: fs::Stack::new(root), | |
| 54 | 42 | #[cfg(debug_assertions)] |
| 55 | 43 | test_mkdir_calls: 0, |
| 56 | 44 | unlink_on_collision: false, |
| @@ -66,58 +54,33 @@ mod cache { · 9 unmodified lines | ||
| 66 | 54 | relative: impl AsRef<Path>, |
| 67 | 55 | mode: git_index::entry::Mode, |
| 68 | 56 | ) -> 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; | |
| 100 | 63 | if components.peek().is_some() || target_is_dir { |
| 101 | 64 | #[cfg(debug_assertions)] |
| 102 | 65 | { |
| 103 | − self.test_mkdir_calls += 1; | |
| 66 | + *mkdir_calls += 1; | |
| 104 | 67 | } |
| 105 | − match std::fs::create_dir(&self.valid) { | |
| 68 | + match std::fs::create_dir(stack.current()) { | |
| 106 | 69 | Ok(()) => {} |
| 107 | 70 | Err(err) if err.kind() == std::io::ErrorKind::AlreadyExists => { |
| 108 | − let meta = self.valid.symlink_metadata()?; | |
| 71 | + let meta = stack.current().symlink_metadata()?; | |
| 109 | 72 | if !meta.is_dir() { |
| 110 | − if self.unlink_on_collision { | |
| 73 | + if unlink_on_collision { | |
| 111 | 74 | if meta.is_symlink() { |
| 112 | − os::remove_symlink(&self.valid)?; | |
| 75 | + os::remove_symlink(stack.current())?; | |
| 113 | 76 | } else { |
| 114 | − std::fs::remove_file(&self.valid)?; | |
| 77 | + std::fs::remove_file(stack.current())?; | |
| 115 | 78 | } |
| 116 | 79 | #[cfg(debug_assertions)] |
| 117 | 80 | { |
| 118 | − self.test_mkdir_calls += 1; | |
| 81 | + *mkdir_calls += 1; | |
| 119 | 82 | } |
| 120 | − std::fs::create_dir(&self.valid)?; | |
| 83 | + std::fs::create_dir(stack.current())?; | |
| 121 | 84 | } else { |
| 122 | 85 | return Err(err); |
| 123 | 86 | } |
| @@ -127,17 +90,8 @@ mod cache { · 3 unmodified lines | ||
| 127 | 90 | } |
| 128 | 91 | } |
| 129 | 92 | 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) | |
| 141 | 95 | } |
| 142 | 96 | } |
| 143 | 97 | } |