1use std::path::PathBuf;
2
3#[cfg(feature = "worktree-archive")]
4pub use gix_archive as archive;
5#[cfg(feature = "excludes")]
6pub use gix_worktree::*;
7#[cfg(feature = "worktree-mutation")]
8pub use gix_worktree_state as state;
9#[cfg(feature = "worktree-stream")]
10pub use gix_worktree_stream as stream;
11
12use crate::{
13 bstr::{BStr, BString},
14 Repository,
15};
16
17#[cfg(feature = "index")]
18pub(crate) type IndexStorage = gix_features::threading::OwnShared<gix_fs::SharedFileSnapshotMut<gix_index::File>>;
19#[cfg(feature = "index")]
21pub type Index = gix_fs::SharedFileSnapshot<gix_index::File>;
22
23#[cfg(feature = "index")]
25#[allow(clippy::large_enum_variant)]
26#[derive(Clone)]
27pub enum IndexPersistedOrInMemory {
28 Persisted(Index),
30 InMemory(gix_index::File),
34}
35
36#[cfg(feature = "index")]
37impl From<Index> for IndexPersistedOrInMemory {
38 fn from(value: Index) -> Self {
39 IndexPersistedOrInMemory::Persisted(value)
40 }
41}
42
43#[cfg(feature = "index")]
44impl From<gix_index::File> for IndexPersistedOrInMemory {
45 fn from(value: gix_index::File) -> Self {
46 IndexPersistedOrInMemory::InMemory(value)
47 }
48}
49
50#[derive(Debug, Clone)]
55pub struct Proxy<'repo> {
56 pub(crate) parent: &'repo Repository,
57 pub(crate) git_dir: PathBuf,
58}
59
60impl<'repo> crate::Worktree<'repo> {
62 pub fn base(&self) -> &'repo std::path::Path {
64 self.path
65 }
66
67 pub fn is_main(&self) -> bool {
71 self.id().is_none()
72 }
73
74 pub fn is_locked(&self) -> bool {
78 Proxy::new(self.parent, self.parent.git_dir()).is_locked()
79 }
80
81 pub fn lock_reason(&self) -> Option<BString> {
86 Proxy::new(self.parent, self.parent.git_dir()).lock_reason()
87 }
88
89 pub fn id(&self) -> Option<&BStr> {
91 id(self.parent.git_dir(), self.parent.common_dir.is_some())
92 }
93
94 pub fn dot_git_exists(&self) -> bool {
98 self.path.join(gix_discover::DOT_GIT_DIR).exists()
99 }
100}
101
102pub(crate) fn id(git_dir: &std::path::Path, has_common_dir: bool) -> Option<&BStr> {
103 if !has_common_dir {
104 return None;
105 }
106 let candidate = gix_path::os_str_into_bstr(git_dir.file_name().expect("at least one directory level"))
107 .expect("no illformed UTF-8");
108 let maybe_worktrees = git_dir.parent()?;
109 (maybe_worktrees.file_name()?.to_str()? == "worktrees").then_some(candidate)
110}
111
112pub mod proxy;
114
115#[cfg(feature = "index")]
117pub mod open_index {
118 #[derive(Debug, thiserror::Error)]
120 #[allow(missing_docs)]
121 pub enum Error {
122 #[error(transparent)]
123 ConfigIndexThreads(#[from] crate::config::key::GenericErrorWithValue),
124 #[error(transparent)]
125 ConfigSkipHash(#[from] crate::config::boolean::Error),
126 #[error(transparent)]
127 IndexFile(#[from] gix_index::file::init::Error),
128 #[error(transparent)]
129 IndexCorrupt(#[from] gix_index::file::verify::Error),
130 }
131
132 impl crate::Worktree<'_> {
133 pub fn open_index(&self) -> Result<gix_index::File, Error> {
135 self.parent.open_index()
136 }
137
138 pub fn index(&self) -> Result<crate::worktree::Index, Error> {
140 self.parent.index()
141 }
142 }
143}
144
145#[cfg(feature = "excludes")]
147pub mod excludes {
148 use crate::AttributeStack;
149
150 #[derive(Debug, thiserror::Error)]
152 #[allow(missing_docs)]
153 pub enum Error {
154 #[error(transparent)]
155 OpenIndex(#[from] crate::worktree::open_index::Error),
156 #[error(transparent)]
157 CreateCache(#[from] crate::config::exclude_stack::Error),
158 }
159
160 impl crate::Worktree<'_> {
161 pub fn excludes(&self, overrides: Option<gix_ignore::Search>) -> Result<AttributeStack<'_>, Error> {
171 let index = self.index()?;
172 Ok(self.parent.excludes(
173 &index,
174 overrides,
175 gix_worktree::stack::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped,
176 )?)
177 }
178 }
179}
180
181#[cfg(feature = "attributes")]
183pub mod attributes {
184 use crate::{AttributeStack, Worktree};
185
186 #[derive(Debug, thiserror::Error)]
188 #[allow(missing_docs)]
189 pub enum Error {
190 #[error(transparent)]
191 OpenIndex(#[from] crate::worktree::open_index::Error),
192 #[error(transparent)]
193 CreateCache(#[from] crate::repository::attributes::Error),
194 }
195
196 impl<'repo> Worktree<'repo> {
197 pub fn attributes(&self, overrides: Option<gix_ignore::Search>) -> Result<AttributeStack<'repo>, Error> {
204 let index = self.index()?;
205 Ok(self.parent.attributes(
206 &index,
207 gix_worktree::stack::state::attributes::Source::WorktreeThenIdMapping,
208 gix_worktree::stack::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped,
209 overrides,
210 )?)
211 }
212
213 pub fn attributes_only(&self) -> Result<AttributeStack<'repo>, Error> {
215 let index = self.index()?;
216 self.parent
217 .attributes_only(
218 &index,
219 gix_worktree::stack::state::attributes::Source::WorktreeThenIdMapping,
220 )
221 .map_err(|err| Error::CreateCache(err.into()))
222 }
223 }
224}
225
226#[cfg(feature = "attributes")]
228pub mod pathspec {
229 use crate::{
230 bstr::BStr,
231 config::{cache::util::ApplyLeniencyDefaultValue, tree::gitoxide},
232 Worktree,
233 };
234
235 #[derive(Debug, thiserror::Error)]
237 #[allow(missing_docs)]
238 pub enum Error {
239 #[error(transparent)]
240 Init(#[from] crate::pathspec::init::Error),
241 #[error(transparent)]
242 OpenIndex(#[from] crate::worktree::open_index::Error),
243 }
244
245 impl<'repo> Worktree<'repo> {
246 pub fn pathspec(
255 &self,
256 patterns: impl IntoIterator<Item = impl AsRef<BStr>>,
257 ) -> Result<crate::Pathspec<'repo>, Error> {
258 let index = self.index()?;
259 let inherit_ignore_case = self
260 .parent
261 .config
262 .resolved
263 .boolean("gitoxide.pathspec.inheritIgnoreCase")
264 .map(|res| {
265 gitoxide::Pathspec::INHERIT_IGNORE_CASE
266 .enrich_error(res)
267 .with_lenient_default_value(
268 self.parent.config.lenient_config,
269 gitoxide::Pathspec::INHERIT_IGNORE_CASE_DEFAULT,
270 )
271 })
272 .transpose()
273 .map_err(|err| Error::Init(crate::pathspec::init::Error::Defaults(err.into())))?
274 .unwrap_or(gitoxide::Pathspec::INHERIT_IGNORE_CASE_DEFAULT);
275 Ok(self.parent.pathspec(
276 true, patterns,
278 inherit_ignore_case,
279 &index,
280 gix_worktree::stack::state::attributes::Source::WorktreeThenIdMapping,
281 )?)
282 }
283 }
284}