Skip to content

Commit ca8f3c2

Browse files
committed
ignore: use named fields in Ignore
The root-specific absolute base now lives alongside the cached matcher state in `Ignore`. Give both fields names to make their different roles clearer.
1 parent 0238a9c commit ca8f3c2

1 file changed

Lines changed: 90 additions & 72 deletions

File tree

crates/ignore/src/dir.rs

Lines changed: 90 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,15 @@ struct IgnoreOptions {
9191

9292
/// Ignore is a matcher useful for recursively walking one or more directories.
9393
#[derive(Clone, Debug)]
94-
pub(crate) struct Ignore(
95-
Arc<IgnoreInner>,
96-
// Parent matchers are cached independently of the root they are used
97-
// from, but matching them still needs the canonicalized path originally
98-
// passed to `add_parents` to rewrite paths relative to that walk root.
99-
Option<Arc<PathBuf>>,
100-
);
94+
pub(crate) struct Ignore {
95+
inner: Arc<IgnoreInner>,
96+
// Parent matchers are cached independently of the path being walked, but
97+
// matching them still needs the canonicalized path originally passed to
98+
// `add_parents`. For example, when walking `/tmp/project/src`, parent
99+
// matchers use `/tmp/project/src` to rewrite `foo.py` before matching it
100+
// against ignore files from `/tmp/project` and its ancestors.
101+
absolute_base: Option<Arc<PathBuf>>,
102+
}
101103

102104
#[derive(Clone, Debug)]
103105
struct IgnoreInner {
@@ -157,20 +159,20 @@ impl Ignore {
157159
/// Return the directory path of this matcher.
158160
#[cfg(test)]
159161
pub(crate) fn path(&self) -> &Path {
160-
&self.0.dir
162+
&self.inner.dir
161163
}
162164

163165
/// Return true if this matcher has no parent.
164166
pub(crate) fn is_root(&self) -> bool {
165-
self.0.parent.is_none()
167+
self.inner.parent.is_none()
166168
}
167169

168170
/// Return this matcher's parent, if one exists.
169171
pub(crate) fn parent(&self) -> Option<Ignore> {
170-
self.0
171-
.parent
172-
.as_ref()
173-
.map(|parent| Ignore(parent.clone(), self.1.clone()))
172+
self.inner.parent.as_ref().map(|parent| Ignore {
173+
inner: parent.clone(),
174+
absolute_base: self.absolute_base.clone(),
175+
})
174176
}
175177

176178
/// Create a new `Ignore` matcher with the parent directories of `dir`.
@@ -181,10 +183,10 @@ impl Ignore {
181183
&self,
182184
path: P,
183185
) -> (Ignore, Option<Error>) {
184-
if !self.0.opts.parents
185-
&& !self.0.opts.git_ignore
186-
&& !self.0.opts.git_exclude
187-
&& !self.0.opts.git_global
186+
if !self.inner.opts.parents
187+
&& !self.inner.opts.git_ignore
188+
&& !self.inner.opts.git_exclude
189+
&& !self.inner.opts.git_global
188190
{
189191
// If we never need info from parent directories, then don't do
190192
// anything.
@@ -213,24 +215,30 @@ impl Ignore {
213215
let mut errs = PartialErrorBuilder::default();
214216
let mut ig = self.clone();
215217
for parent in parents.into_iter().rev() {
216-
let mut compiled = self.0.compiled.write().unwrap();
218+
let mut compiled = self.inner.compiled.write().unwrap();
217219
if let Some(weak) = compiled.get(parent.as_os_str()) {
218220
if let Some(prebuilt) = weak.upgrade() {
219-
ig = Ignore(prebuilt, Some(absolute_base.clone()));
221+
ig = Ignore {
222+
inner: prebuilt,
223+
absolute_base: Some(absolute_base.clone()),
224+
};
220225
continue;
221226
}
222227
}
223228
let (mut igtmp, err) = ig.add_child_path(parent);
224229
errs.maybe_push(err);
225230
igtmp.is_absolute_parent = true;
226231
igtmp.has_git =
227-
if self.0.opts.require_git && self.0.opts.git_ignore {
232+
if self.inner.opts.require_git && self.inner.opts.git_ignore {
228233
parent.join(".git").exists() || parent.join(".jj").exists()
229234
} else {
230235
false
231236
};
232237
let ig_arc = Arc::new(igtmp);
233-
ig = Ignore(ig_arc.clone(), Some(absolute_base.clone()));
238+
ig = Ignore {
239+
inner: ig_arc.clone(),
240+
absolute_base: Some(absolute_base.clone()),
241+
};
234242
compiled.insert(
235243
parent.as_os_str().to_os_string(),
236244
Arc::downgrade(&ig_arc),
@@ -252,13 +260,19 @@ impl Ignore {
252260
dir: P,
253261
) -> (Ignore, Option<Error>) {
254262
let (ig, err) = self.add_child_path(dir.as_ref());
255-
(Ignore(Arc::new(ig), self.1.clone()), err)
263+
(
264+
Ignore {
265+
inner: Arc::new(ig),
266+
absolute_base: self.absolute_base.clone(),
267+
},
268+
err,
269+
)
256270
}
257271

258272
/// Like add_child, but takes a full path and returns an IgnoreInner.
259273
fn add_child_path(&self, dir: &Path) -> (IgnoreInner, Option<Error>) {
260-
let check_vcs_dir = self.0.opts.require_git
261-
&& (self.0.opts.git_ignore || self.0.opts.git_exclude);
274+
let check_vcs_dir = self.inner.opts.require_git
275+
&& (self.inner.opts.git_ignore || self.inner.opts.git_exclude);
262276
let git_type = if check_vcs_dir {
263277
dir.join(".git").metadata().ok().map(|md| md.file_type())
264278
} else {
@@ -268,44 +282,45 @@ impl Ignore {
268282
check_vcs_dir && (git_type.is_some() || dir.join(".jj").exists());
269283

270284
let mut errs = PartialErrorBuilder::default();
271-
let custom_ig_matcher = if self.0.custom_ignore_filenames.is_empty() {
272-
Gitignore::empty()
273-
} else {
274-
let (m, err) = create_gitignore(
275-
&dir,
276-
&dir,
277-
&self.0.custom_ignore_filenames,
278-
self.0.opts.ignore_case_insensitive,
279-
);
280-
errs.maybe_push(err);
281-
m
282-
};
283-
let ig_matcher = if !self.0.opts.ignore {
285+
let custom_ig_matcher =
286+
if self.inner.custom_ignore_filenames.is_empty() {
287+
Gitignore::empty()
288+
} else {
289+
let (m, err) = create_gitignore(
290+
&dir,
291+
&dir,
292+
&self.inner.custom_ignore_filenames,
293+
self.inner.opts.ignore_case_insensitive,
294+
);
295+
errs.maybe_push(err);
296+
m
297+
};
298+
let ig_matcher = if !self.inner.opts.ignore {
284299
Gitignore::empty()
285300
} else {
286301
let (m, err) = create_gitignore(
287302
&dir,
288303
&dir,
289304
&[".ignore"],
290-
self.0.opts.ignore_case_insensitive,
305+
self.inner.opts.ignore_case_insensitive,
291306
);
292307
errs.maybe_push(err);
293308
m
294309
};
295-
let gi_matcher = if !self.0.opts.git_ignore {
310+
let gi_matcher = if !self.inner.opts.git_ignore {
296311
Gitignore::empty()
297312
} else {
298313
let (m, err) = create_gitignore(
299314
&dir,
300315
&dir,
301316
&[".gitignore"],
302-
self.0.opts.ignore_case_insensitive,
317+
self.inner.opts.ignore_case_insensitive,
303318
);
304319
errs.maybe_push(err);
305320
m
306321
};
307322

308-
let gi_exclude_matcher = if !self.0.opts.git_exclude {
323+
let gi_exclude_matcher = if !self.inner.opts.git_exclude {
309324
Gitignore::empty()
310325
} else {
311326
match resolve_git_commondir(dir, git_type) {
@@ -314,7 +329,7 @@ impl Ignore {
314329
&dir,
315330
&git_dir,
316331
&["info/exclude"],
317-
self.0.opts.ignore_case_insensitive,
332+
self.inner.opts.ignore_case_insensitive,
318333
);
319334
errs.maybe_push(err);
320335
m
@@ -326,35 +341,38 @@ impl Ignore {
326341
}
327342
};
328343
let ig = IgnoreInner {
329-
compiled: self.0.compiled.clone(),
344+
compiled: self.inner.compiled.clone(),
330345
dir: dir.to_path_buf(),
331-
overrides: self.0.overrides.clone(),
332-
types: self.0.types.clone(),
333-
parent: Some(self.0.clone()),
346+
overrides: self.inner.overrides.clone(),
347+
types: self.inner.types.clone(),
348+
parent: Some(self.inner.clone()),
334349
is_absolute_parent: false,
335350
global_gitignores_relative_to: self
336-
.0
351+
.inner
337352
.global_gitignores_relative_to
338353
.clone(),
339-
explicit_ignores: self.0.explicit_ignores.clone(),
340-
custom_ignore_filenames: self.0.custom_ignore_filenames.clone(),
354+
explicit_ignores: self.inner.explicit_ignores.clone(),
355+
custom_ignore_filenames: self
356+
.inner
357+
.custom_ignore_filenames
358+
.clone(),
341359
custom_ignore_matcher: custom_ig_matcher,
342360
ignore_matcher: ig_matcher,
343-
git_global_matcher: self.0.git_global_matcher.clone(),
361+
git_global_matcher: self.inner.git_global_matcher.clone(),
344362
git_ignore_matcher: gi_matcher,
345363
git_exclude_matcher: gi_exclude_matcher,
346364
has_git,
347-
opts: self.0.opts,
365+
opts: self.inner.opts,
348366
};
349367
(ig, errs.into_error_option())
350368
}
351369

352370
/// Returns true if at least one type of ignore rule should be matched.
353371
fn has_any_ignore_rules(&self) -> bool {
354-
let opts = self.0.opts;
372+
let opts = self.inner.opts;
355373
let has_custom_ignore_files =
356-
!self.0.custom_ignore_filenames.is_empty();
357-
let has_explicit_ignores = !self.0.explicit_ignores.is_empty();
374+
!self.inner.custom_ignore_filenames.is_empty();
375+
let has_explicit_ignores = !self.inner.explicit_ignores.is_empty();
358376

359377
opts.ignore
360378
|| opts.git_global
@@ -370,7 +388,7 @@ impl Ignore {
370388
dent: &DirEntry,
371389
) -> Match<IgnoreMatch<'a>> {
372390
let m = self.matched(dent.path(), dent.is_dir());
373-
if m.is_none() && self.0.opts.hidden && is_hidden(dent) {
391+
if m.is_none() && self.inner.opts.hidden && is_hidden(dent) {
374392
return Match::Ignore(IgnoreMatch::hidden());
375393
}
376394
m
@@ -395,9 +413,9 @@ impl Ignore {
395413
// regardless of whether it's whitelist/ignore, then we quit and
396414
// return that result immediately. Overrides have the highest
397415
// precedence.
398-
if !self.0.overrides.is_empty() {
416+
if !self.inner.overrides.is_empty() {
399417
let mat = self
400-
.0
418+
.inner
401419
.overrides
402420
.matched(path, is_dir)
403421
.map(IgnoreMatch::overrides);
@@ -414,9 +432,9 @@ impl Ignore {
414432
whitelisted = mat;
415433
}
416434
}
417-
if !self.0.types.is_empty() {
435+
if !self.inner.types.is_empty() {
418436
let mat =
419-
self.0.types.matched(path, is_dir).map(IgnoreMatch::types);
437+
self.inner.types.matched(path, is_dir).map(IgnoreMatch::types);
420438
if mat.is_ignore() {
421439
return mat;
422440
} else if mat.is_whitelist() {
@@ -440,8 +458,8 @@ impl Ignore {
440458
mut m_gi_exclude,
441459
mut m_explicit,
442460
) = (Match::None, Match::None, Match::None, Match::None, Match::None);
443-
let any_git =
444-
!self.0.opts.require_git || self.parents().any(|ig| ig.0.has_git);
461+
let any_git = !self.inner.opts.require_git
462+
|| self.parents().any(|ig| ig.0.has_git);
445463
let mut saw_git = false;
446464
for ig in self.parents().take_while(|ig| !ig.0.is_absolute_parent) {
447465
if m_custom_ignore.is_none() {
@@ -470,7 +488,7 @@ impl Ignore {
470488
}
471489
saw_git = saw_git || ig.0.has_git;
472490
}
473-
if self.0.opts.parents {
491+
if self.inner.opts.parents {
474492
if let Some(abs_parent_path) = self.absolute_base() {
475493
// What we want to do here is take the absolute base path of
476494
// this directory and join it with the path we're searching.
@@ -532,14 +550,14 @@ impl Ignore {
532550
}
533551
}
534552
}
535-
for gi in self.0.explicit_ignores.iter().rev() {
553+
for gi in self.inner.explicit_ignores.iter().rev() {
536554
if !m_explicit.is_none() {
537555
break;
538556
}
539557
m_explicit = gi.matched(&path, is_dir).map(IgnoreMatch::gitignore);
540558
}
541559
let m_global = if any_git {
542-
self.0
560+
self.inner
543561
.git_global_matcher
544562
.matched(&path, is_dir)
545563
.map(IgnoreMatch::gitignore)
@@ -557,17 +575,16 @@ impl Ignore {
557575

558576
/// Returns an iterator over parent ignore matchers, including this one.
559577
pub(crate) fn parents(&self) -> Parents<'_> {
560-
Parents(Some(IgnoreRef(&self.0)))
578+
Parents(Some(IgnoreRef(&self.inner)))
561579
}
562580

563581
/// Returns the first absolute path of the first absolute parent, if
564582
/// one exists.
565583
fn absolute_base(&self) -> Option<&Path> {
566-
self.1.as_ref().map(|p| &***p)
584+
self.absolute_base.as_ref().map(|p| &***p)
567585
}
568586
}
569587

570-
/// An iterator over all parents of an ignore matcher, including itself.
571588
#[derive(Clone, Copy)]
572589
pub(crate) struct IgnoreRef<'a>(&'a IgnoreInner);
573590

@@ -581,6 +598,7 @@ impl IgnoreRef<'_> {
581598
}
582599
}
583600

601+
/// An iterator over all parents of an ignore matcher, including itself.
584602
pub(crate) struct Parents<'a>(Option<IgnoreRef<'a>>);
585603

586604
impl<'a> Iterator for Parents<'a> {
@@ -685,8 +703,8 @@ impl IgnoreBuilder {
685703
Gitignore::empty()
686704
};
687705

688-
Ignore(
689-
Arc::new(IgnoreInner {
706+
Ignore {
707+
inner: Arc::new(IgnoreInner {
690708
compiled: Arc::new(RwLock::new(HashMap::new())),
691709
dir: self.dir.clone(),
692710
overrides: self.overrides.clone(),
@@ -706,8 +724,8 @@ impl IgnoreBuilder {
706724
has_git: false,
707725
opts: self.opts,
708726
}),
709-
None,
710-
)
727+
absolute_base: None,
728+
}
711729
}
712730

713731
/// Set the current directory used for matching global gitignores.
@@ -1289,7 +1307,7 @@ mod tests {
12891307
let (tests, err) = tests_parents.add_child(td.path().join("tests"));
12901308
assert!(err.is_none());
12911309

1292-
assert!(Arc::ptr_eq(&src_parents.0, &tests_parents.0));
1310+
assert!(Arc::ptr_eq(&src_parents.inner, &tests_parents.inner));
12931311
assert!(src.matched("build", true).is_none());
12941312
assert!(tests.matched("build", true).is_ignore());
12951313
}

0 commit comments

Comments
 (0)