@@ -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 ) ]
103105struct 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 ) ]
572589pub ( 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.
584602pub ( crate ) struct Parents < ' a > ( Option < IgnoreRef < ' a > > ) ;
585603
586604impl < ' 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