]> git.proxmox.com Git - rustc.git/blob - vendor/gix-worktree/src/cache/mod.rs
New upstream version 1.73.0+dfsg1
[rustc.git] / vendor / gix-worktree / src / cache / mod.rs
1 #![allow(missing_docs)]
2 use std::path::{Path, PathBuf};
3
4 use bstr::{BStr, ByteSlice};
5 use gix_hash::oid;
6
7 use super::Cache;
8 use crate::PathIdMapping;
9
10 /// Various aggregate numbers collected from when the corresponding [`Cache`] was instantiated.
11 #[derive(Default, Clone, Copy, Debug)]
12 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13 pub struct Statistics {
14 /// The amount of platforms created to do further matching.
15 pub platforms: usize,
16 /// Information about the stack delegate.
17 pub delegate: delegate::Statistics,
18 /// Information about attributes
19 pub attributes: state::attributes::Statistics,
20 /// Information about the ignore stack
21 pub ignore: state::ignore::Statistics,
22 }
23
24 #[derive(Clone)]
25 pub enum State {
26 /// Useful for checkout where directories need creation, but we need to access attributes as well.
27 CreateDirectoryAndAttributesStack {
28 /// If there is a symlink or a file in our path, try to unlink it before creating the directory.
29 unlink_on_collision: bool,
30 /// State to handle attribute information
31 attributes: state::Attributes,
32 },
33 /// Used when adding files, requiring access to both attributes and ignore information, for example during add operations.
34 AttributesAndIgnoreStack {
35 /// State to handle attribute information
36 attributes: state::Attributes,
37 /// State to handle exclusion information
38 ignore: state::Ignore,
39 },
40 /// Used when providing worktree status information.
41 IgnoreStack(state::Ignore),
42 }
43
44 #[must_use]
45 pub struct Platform<'a> {
46 parent: &'a Cache,
47 is_dir: Option<bool>,
48 }
49
50 /// Initialization
51 impl Cache {
52 /// Create a new instance with `worktree_root` being the base for all future paths we match.
53 /// `state` defines the capabilities of the cache.
54 /// The `case` configures attribute and exclusion case sensitivity at *query time*, which should match the case that
55 /// `state` might be configured with.
56 /// `buf` is used when reading files, and `id_mappings` should have been created with [`State::id_mappings_from_index()`].
57 pub fn new(
58 worktree_root: impl Into<PathBuf>,
59 state: State,
60 case: gix_glob::pattern::Case,
61 buf: Vec<u8>,
62 id_mappings: Vec<PathIdMapping>,
63 ) -> Self {
64 let root = worktree_root.into();
65 Cache {
66 stack: gix_fs::Stack::new(root),
67 state,
68 case,
69 buf,
70 id_mappings,
71 statistics: Statistics::default(),
72 }
73 }
74 }
75
76 /// Entry points for attribute query
77 impl Cache {
78 /// Append the `relative` path to the root directory of the cache and efficiently create leading directories, while assuring that no
79 /// symlinks are in that path.
80 /// Unless `is_dir` is known with `Some(…)`, then `relative` points to a directory itself in which case the entire resulting
81 /// path is created as directory. If it's not known it is assumed to be a file.
82 /// `find` maybe used to lookup objects from an [id mapping][crate::cache::State::id_mappings_from_index()], with mappnigs
83 ///
84 /// Provide access to cached information for that `relative` path via the returned platform.
85 pub fn at_path<Find, E>(
86 &mut self,
87 relative: impl AsRef<Path>,
88 is_dir: Option<bool>,
89 find: Find,
90 ) -> std::io::Result<Platform<'_>>
91 where
92 Find: for<'a> FnMut(&oid, &'a mut Vec<u8>) -> Result<gix_object::BlobRef<'a>, E>,
93 E: std::error::Error + Send + Sync + 'static,
94 {
95 self.statistics.platforms += 1;
96 let mut delegate = StackDelegate {
97 state: &mut self.state,
98 buf: &mut self.buf,
99 is_dir: is_dir.unwrap_or(false),
100 id_mappings: &self.id_mappings,
101 find,
102 case: self.case,
103 statistics: &mut self.statistics,
104 };
105 self.stack.make_relative_path_current(relative, &mut delegate)?;
106 Ok(Platform { parent: self, is_dir })
107 }
108
109 /// Obtain a platform for lookups from a repo-`relative` path, typically obtained from an index entry. `is_dir` should reflect
110 /// whether it's a directory or not, or left at `None` if unknown.
111 /// `find` maybe used to lookup objects from an [id mapping][crate::cache::State::id_mappings_from_index()].
112 /// All effects are similar to [`at_path()`][Self::at_path()].
113 ///
114 /// If `relative` ends with `/` and `is_dir` is `None`, it is automatically assumed to be a directory.
115 ///
116 /// ### Panics
117 ///
118 /// on illformed UTF8 in `relative`
119 pub fn at_entry<'r, Find, E>(
120 &mut self,
121 relative: impl Into<&'r BStr>,
122 is_dir: Option<bool>,
123 find: Find,
124 ) -> std::io::Result<Platform<'_>>
125 where
126 Find: for<'a> FnMut(&oid, &'a mut Vec<u8>) -> Result<gix_object::BlobRef<'a>, E>,
127 E: std::error::Error + Send + Sync + 'static,
128 {
129 let relative = relative.into();
130 let relative_path = gix_path::from_bstr(relative);
131
132 self.at_path(
133 relative_path,
134 is_dir.or_else(|| relative.ends_with_str("/").then_some(true)),
135 find,
136 )
137 }
138 }
139
140 /// Mutation
141 impl Cache {
142 /// Reset the statistics after returning them.
143 pub fn take_statistics(&mut self) -> Statistics {
144 std::mem::take(&mut self.statistics)
145 }
146
147 /// Return our state for applying changes.
148 pub fn state_mut(&mut self) -> &mut State {
149 &mut self.state
150 }
151 }
152
153 /// Access
154 impl Cache {
155 /// Return the statistics we gathered thus far.
156 pub fn statistics(&self) -> &Statistics {
157 &self.statistics
158 }
159 /// Return the state for introspection.
160 pub fn state(&self) -> &State {
161 &self.state
162 }
163
164 /// Return the base path against which all entries or paths should be relative to when querying.
165 ///
166 /// Note that this path _may_ not be canonicalized.
167 pub fn base(&self) -> &Path {
168 self.stack.root()
169 }
170 }
171
172 ///
173 pub mod delegate;
174 use delegate::StackDelegate;
175
176 mod platform;
177 ///
178 pub mod state;