]> git.proxmox.com Git - rustc.git/blob - vendor/gix-worktree/src/fs/cache/mod.rs
New upstream version 1.70.0+dfsg2
[rustc.git] / vendor / gix-worktree / src / fs / 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::{fs, fs::PathOidMapping};
9
10 #[derive(Clone)]
11 pub enum State {
12 /// Useful for checkout where directories need creation, but we need to access attributes as well.
13 CreateDirectoryAndAttributesStack {
14 /// If there is a symlink or a file in our path, try to unlink it before creating the directory.
15 unlink_on_collision: bool,
16
17 /// just for testing
18 #[cfg(debug_assertions)]
19 test_mkdir_calls: usize,
20 /// State to handle attribute information
21 attributes: state::Attributes,
22 },
23 /// Used when adding files, requiring access to both attributes and ignore information, for example during add operations.
24 AttributesAndIgnoreStack {
25 /// State to handle attribute information
26 attributes: state::Attributes,
27 /// State to handle exclusion information
28 ignore: state::Ignore,
29 },
30 /// Used when providing worktree status information.
31 IgnoreStack(state::Ignore),
32 }
33
34 #[cfg(debug_assertions)]
35 impl Cache {
36 pub fn set_case(&mut self, case: gix_glob::pattern::Case) {
37 self.case = case;
38 }
39 pub fn num_mkdir_calls(&self) -> usize {
40 match self.state {
41 State::CreateDirectoryAndAttributesStack { test_mkdir_calls, .. } => test_mkdir_calls,
42 _ => 0,
43 }
44 }
45
46 pub fn reset_mkdir_calls(&mut self) {
47 if let State::CreateDirectoryAndAttributesStack { test_mkdir_calls, .. } = &mut self.state {
48 *test_mkdir_calls = 0;
49 }
50 }
51
52 pub fn unlink_on_collision(&mut self, value: bool) {
53 if let State::CreateDirectoryAndAttributesStack {
54 unlink_on_collision, ..
55 } = &mut self.state
56 {
57 *unlink_on_collision = value;
58 }
59 }
60 }
61
62 #[must_use]
63 pub struct Platform<'a> {
64 parent: &'a Cache,
65 is_dir: Option<bool>,
66 }
67
68 impl Cache {
69 /// Create a new instance with `worktree_root` being the base for all future paths we handle, assuming it to be valid which includes
70 /// symbolic links to be included in it as well.
71 /// The `case` configures attribute and exclusion query case sensitivity.
72 pub fn new(
73 worktree_root: impl Into<PathBuf>,
74 state: State,
75 case: gix_glob::pattern::Case,
76 buf: Vec<u8>,
77 attribute_files_in_index: Vec<PathOidMapping>,
78 ) -> Self {
79 let root = worktree_root.into();
80 Cache {
81 stack: fs::Stack::new(root),
82 state,
83 case,
84 buf,
85 attribute_files_in_index,
86 }
87 }
88
89 /// Append the `relative` path to the root directory the cache contains and efficiently create leading directories
90 /// unless `is_dir` is known (`Some(…)`) then `relative` points to a directory itself in which case the entire resulting
91 /// path is created as directory. If it's not known it is assumed to be a file.
92 ///
93 /// Provide access to cached information for that `relative` entry via the platform returned.
94 pub fn at_path<Find, E>(
95 &mut self,
96 relative: impl AsRef<Path>,
97 is_dir: Option<bool>,
98 find: Find,
99 ) -> std::io::Result<Platform<'_>>
100 where
101 Find: for<'a> FnMut(&oid, &'a mut Vec<u8>) -> Result<gix_object::BlobRef<'a>, E>,
102 E: std::error::Error + Send + Sync + 'static,
103 {
104 let mut delegate = platform::StackDelegate {
105 state: &mut self.state,
106 buf: &mut self.buf,
107 is_dir: is_dir.unwrap_or(false),
108 attribute_files_in_index: &self.attribute_files_in_index,
109 find,
110 };
111 self.stack.make_relative_path_current(relative, &mut delegate)?;
112 Ok(Platform { parent: self, is_dir })
113 }
114
115 /// **Panics** on illformed UTF8 in `relative`
116 // TODO: more docs
117 pub fn at_entry<'r, Find, E>(
118 &mut self,
119 relative: impl Into<&'r BStr>,
120 is_dir: Option<bool>,
121 find: Find,
122 ) -> std::io::Result<Platform<'_>>
123 where
124 Find: for<'a> FnMut(&oid, &'a mut Vec<u8>) -> Result<gix_object::BlobRef<'a>, E>,
125 E: std::error::Error + Send + Sync + 'static,
126 {
127 let relative = relative.into();
128 let relative_path = gix_path::from_bstr(relative);
129
130 self.at_path(
131 relative_path,
132 is_dir.or_else(|| relative.ends_with_str("/").then_some(true)),
133 // is_dir,
134 find,
135 )
136 }
137
138 /// Return the base path against which all entries or paths should be relative to when querying.
139 ///
140 /// Note that this path _may_ not be canonicalized.
141 pub fn base(&self) -> &Path {
142 self.stack.root()
143 }
144 }
145
146 mod platform;
147 ///
148 pub mod state;