gix/repository/
dirwalk.rs1use std::sync::atomic::AtomicBool;
2
3use crate::{
4 bstr::{BStr, BString},
5 config, dirwalk, is_dir_to_mode,
6 util::OwnedOrStaticAtomicBool,
7 worktree::IndexPersistedOrInMemory,
8 Repository,
9};
10
11impl Repository {
12 pub fn dirwalk_options(&self) -> Result<dirwalk::Options, config::boolean::Error> {
16 Ok(dirwalk::Options::from_fs_caps(self.filesystem_options()?))
17 }
18
19 pub fn dirwalk(
35 &self,
36 index: &gix_index::State,
37 patterns: impl IntoIterator<Item = impl AsRef<BStr>>,
38 should_interrupt: &AtomicBool,
39 options: dirwalk::Options,
40 delegate: &mut dyn gix_dir::walk::Delegate,
41 ) -> Result<dirwalk::Outcome<'_>, dirwalk::Error> {
42 let _span = gix_trace::coarse!("gix::dirwalk");
43 let workdir = self.workdir().ok_or(dirwalk::Error::MissingWorkDir)?;
44 let mut excludes = self.excludes(
45 index,
46 None,
47 crate::worktree::stack::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped,
48 )?;
49 let mut pathspec = self.pathspec(
50 options.empty_patterns_match_prefix, patterns,
52 true, index,
54 crate::worktree::stack::state::attributes::Source::WorktreeThenIdMapping,
55 )?;
56
57 let git_dir_realpath =
58 crate::path::realpath_opts(self.git_dir(), self.current_dir(), crate::path::realpath::MAX_SYMLINKS)?;
59 let fs_caps = self.filesystem_options()?;
60 let accelerate_lookup = fs_caps.ignore_case.then(|| index.prepare_icase_backing());
61 let mut opts = gix_dir::walk::Options::from(options);
62 let worktree_relative_worktree_dirs_storage;
63 if let Some(workdir) = self.workdir().filter(|_| opts.for_deletion.is_some()) {
64 let linked_worktrees = self.worktrees()?;
65 if !linked_worktrees.is_empty() {
66 let real_workdir = gix_path::realpath_opts(
67 workdir,
68 self.options.current_dir_or_empty(),
69 gix_path::realpath::MAX_SYMLINKS,
70 )?;
71 worktree_relative_worktree_dirs_storage = linked_worktrees
72 .into_iter()
73 .filter_map(|proxy| proxy.base().ok())
74 .filter_map(|base| base.strip_prefix(&real_workdir).map(ToOwned::to_owned).ok())
75 .map(|rela_path| {
76 gix_path::to_unix_separators_on_windows(gix_path::into_bstr(rela_path)).into_owned()
77 })
78 .collect();
79 opts.worktree_relative_worktree_dirs = Some(&worktree_relative_worktree_dirs_storage);
80 }
81 }
82 let (outcome, traversal_root) = gix_dir::walk(
83 workdir,
84 gix_dir::walk::Context {
85 should_interrupt: Some(should_interrupt),
86 git_dir_realpath: git_dir_realpath.as_ref(),
87 current_dir: self.current_dir(),
88 index,
89 ignore_case_index_lookup: accelerate_lookup.as_ref(),
90 pathspec: &mut pathspec.search,
91 pathspec_attributes: &mut |relative_path, case, is_dir, out| {
92 let stack = pathspec
93 .stack
94 .as_mut()
95 .expect("can only be called if attributes are used in patterns");
96 stack
97 .set_case(case)
98 .at_entry(relative_path, Some(is_dir_to_mode(is_dir)), &self.objects)
99 .is_ok_and(|platform| platform.matching_attributes(out))
100 },
101 excludes: Some(&mut excludes.inner),
102 objects: &self.objects,
103 explicit_traversal_root: (!options.empty_patterns_match_prefix).then_some(workdir),
104 },
105 opts,
106 delegate,
107 )?;
108
109 Ok(dirwalk::Outcome {
110 dirwalk: outcome,
111 traversal_root,
112 excludes,
113 pathspec,
114 })
115 }
116
117 pub fn dirwalk_iter(
123 &self,
124 index: impl Into<IndexPersistedOrInMemory>,
125 patterns: impl IntoIterator<Item = impl Into<BString>>,
126 should_interrupt: OwnedOrStaticAtomicBool,
127 options: dirwalk::Options,
128 ) -> Result<dirwalk::Iter, dirwalk::iter::Error> {
129 dirwalk::Iter::new(
130 self,
131 index.into(),
132 patterns.into_iter().map(Into::into).collect(),
133 should_interrupt,
134 options,
135 )
136 }
137}