Skip to content

Commit 7217042

Browse files
committed
fix!: leave more control to the user when creating pathspecs
1 parent d7ff656 commit 7217042

File tree

3 files changed

+52
-35
lines changed

3 files changed

+52
-35
lines changed

gitoxide-core/src/repository/clean.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ pub(crate) mod function {
2929
use gix::dir::walk::ForDeletionMode::*;
3030
use gix::dir::{walk, EntryRef};
3131
use std::borrow::Cow;
32-
use std::path::Path;
3332

3433
pub fn clean(
3534
repo: gix::Repository,
@@ -75,12 +74,13 @@ pub(crate) mod function {
7574
.emit_untracked(collapse_directories)
7675
.emit_ignored(Some(collapse_directories))
7776
.emit_empty_directories(true);
78-
repo.dirwalk(&index, patterns, options, &mut collect)?;
79-
let prefix = repo.prefix()?.unwrap_or(Path::new(""));
80-
let prefix_len = if prefix.as_os_str().is_empty() {
81-
0
82-
} else {
83-
prefix.to_str().map_or(0, |s| s.len() + 1 /* slash */)
77+
let actual_root = repo.dirwalk(&index, patterns, options, &mut collect)?.traversal_root;
78+
let prefix_len = {
79+
let prefix = actual_root
80+
.strip_prefix(repo.work_dir().expect("definitely set after successful walk"))
81+
.expect("actual root is always inside workdir")
82+
.as_os_str();
83+
prefix.len() + if prefix.is_empty() { 0 } else { 1 } // slash
8484
};
8585

8686
let entries = collect.inner.into_entries_by_path();

gitoxide-core/src/repository/status.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -87,15 +87,16 @@ pub fn show(
8787
let repo = repo.clone().into_sync();
8888
let index = &index;
8989
let collect = &mut collect;
90-
move || {
90+
move || -> anyhow::Result<_> {
9191
let repo = repo.to_thread_local();
92-
repo.dirwalk(
92+
let outcome = repo.dirwalk(
9393
index,
9494
pathspecs,
9595
repo.dirwalk_options()?
9696
.emit_untracked(gix::dir::walk::EmissionMode::CollapseDirectory),
9797
collect,
98-
)
98+
)?;
99+
Ok((outcome.dirwalk, outcome.traversal_root))
99100
}
100101
})?;
101102

@@ -112,7 +113,7 @@ pub fn show(
112113
options,
113114
)?;
114115

115-
let walk_outcome = walk_outcome.join().expect("no panic")?;
116+
let (walk_outcome, _actual_root) = walk_outcome.join().expect("no panic")?;
116117
Ok((outcome, walk_outcome))
117118
})?;
118119

gix/src/repository/dirwalk.rs

+40-24
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::bstr::BStr;
2-
use crate::{config, dirwalk, Repository};
2+
use crate::{config, dirwalk, AttributeStack, Pathspec, Repository};
33
use std::path::PathBuf;
44

55
/// The error returned by [dirwalk()](Repository::dirwalk()).
@@ -20,6 +20,19 @@ pub enum Error {
2020
FilesystemOptions(#[from] config::boolean::Error),
2121
}
2222

23+
/// The outcome of the [dirwalk()](Repository::dirwalk).
24+
pub struct Outcome<'repo> {
25+
/// The excludes stack used for the dirwalk, for access of `.gitignore` information.
26+
pub excludes: AttributeStack<'repo>,
27+
/// The pathspecs used to guide the operation,
28+
pub pathspec: Pathspec<'repo>,
29+
/// The root actually being used for the traversal, and useful to transform the paths returned for the user.
30+
/// It's always within the [`work-dir`](Repository::work_dir).
31+
pub traversal_root: PathBuf,
32+
/// The actual result of the dirwalk.
33+
pub dirwalk: gix_dir::walk::Outcome,
34+
}
35+
2336
impl Repository {
2437
/// Return default options suitable for performing a directory walk on this repository.
2538
///
@@ -42,54 +55,57 @@ impl Repository {
4255
patterns: impl IntoIterator<Item = impl AsRef<BStr>>,
4356
options: dirwalk::Options,
4457
delegate: &mut dyn gix_dir::walk::Delegate,
45-
) -> Result<(gix_dir::walk::Outcome, PathBuf), Error> {
58+
) -> Result<Outcome<'_>, Error> {
4659
let _span = gix_trace::coarse!("gix::dirwalk");
4760
let workdir = self.work_dir().ok_or(Error::MissinWorkDir)?;
48-
let mut excludes = self
49-
.excludes(
50-
index,
51-
None,
52-
crate::worktree::stack::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped,
53-
)?
54-
.detach();
55-
let (mut pathspec, mut maybe_attributes) = self
56-
.pathspec(
57-
patterns,
58-
true, /* inherit ignore case */
59-
index,
60-
crate::worktree::stack::state::attributes::Source::WorktreeThenIdMapping,
61-
)?
62-
.into_parts();
63-
gix_trace::debug!(patterns = ?pathspec.patterns().map(|p| p.path()).collect::<Vec<_>>());
61+
let mut excludes = self.excludes(
62+
index,
63+
None,
64+
crate::worktree::stack::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped,
65+
)?;
66+
let mut pathspec = self.pathspec(
67+
patterns,
68+
true, /* inherit ignore case */
69+
index,
70+
crate::worktree::stack::state::attributes::Source::WorktreeThenIdMapping,
71+
)?;
72+
gix_trace::debug!(longest_prefix = ?pathspec.search.longest_common_directory(), prefix_dir = ?pathspec.search.prefix_directory(),patterns = ?pathspec.search.patterns().map(|p| p.path()).collect::<Vec<_>>());
6473

6574
let git_dir_realpath =
6675
crate::path::realpath_opts(self.git_dir(), self.current_dir(), crate::path::realpath::MAX_SYMLINKS)?;
6776
let fs_caps = self.filesystem_options()?;
6877
let accelerate_lookup = fs_caps.ignore_case.then(|| index.prepare_icase_backing());
69-
gix_dir::walk(
78+
let (outcome, traversal_root) = gix_dir::walk(
7079
workdir,
7180
gix_dir::walk::Context {
7281
git_dir_realpath: git_dir_realpath.as_ref(),
7382
current_dir: self.current_dir(),
7483
index,
7584
ignore_case_index_lookup: accelerate_lookup.as_ref(),
76-
pathspec: &mut pathspec,
85+
pathspec: &mut pathspec.search,
7786
pathspec_attributes: &mut |relative_path, case, is_dir, out| {
78-
let stack = maybe_attributes
87+
let stack = pathspec
88+
.stack
7989
.as_mut()
8090
.expect("can only be called if attributes are used in patterns");
8191
stack
8292
.set_case(case)
8393
.at_entry(relative_path, Some(is_dir), &self.objects)
8494
.map_or(false, |platform| platform.matching_attributes(out))
8595
},
86-
excludes: Some(&mut excludes),
96+
excludes: Some(&mut excludes.inner),
8797
objects: &self.objects,
8898
explicit_traversal_root: None,
8999
},
90100
options.into(),
91101
delegate,
92-
)
93-
.map_err(Into::into)
102+
)?;
103+
104+
Ok(Outcome {
105+
dirwalk: outcome,
106+
traversal_root,
107+
excludes,
108+
pathspec,
109+
})
94110
}
95111
}

0 commit comments

Comments
 (0)