26
26
*/
27
27
#define FILTER_SHOWN_BUT_REVISIT (1<<21)
28
28
29
+ struct subfilter {
30
+ struct filter * filter ;
31
+ struct oidset seen ;
32
+ struct oidset omits ;
33
+ struct object_id skip_tree ;
34
+ unsigned is_skipping_tree : 1 ;
35
+ };
36
+
29
37
struct filter {
30
38
enum list_objects_filter_result (* filter_object_fn )(
31
39
struct repository * r ,
@@ -36,6 +44,13 @@ struct filter {
36
44
struct oidset * omits ,
37
45
void * filter_data );
38
46
47
+ /*
48
+ * Optional. If this function is supplied and the filter needs to
49
+ * collect omits, then this function is called once before free_fn is
50
+ * called.
51
+ */
52
+ void (* finalize_omits_fn )(struct oidset * omits , void * filter_data );
53
+
39
54
void (* free_fn )(void * filter_data );
40
55
41
56
void * filter_data ;
@@ -471,6 +486,147 @@ static void filter_sparse_oid__init(
471
486
filter -> free_fn = filter_sparse_free ;
472
487
}
473
488
489
+ /* A filter which only shows objects shown by all sub-filters. */
490
+ struct combine_filter_data {
491
+ struct subfilter * sub ;
492
+ size_t nr ;
493
+ };
494
+
495
+ static int should_delegate (enum list_objects_filter_situation filter_situation ,
496
+ struct object * obj ,
497
+ struct subfilter * sub )
498
+ {
499
+ if (!sub -> is_skipping_tree )
500
+ return 1 ;
501
+ if (filter_situation == LOFS_END_TREE &&
502
+ oideq (& obj -> oid , & sub -> skip_tree )) {
503
+ sub -> is_skipping_tree = 0 ;
504
+ return 1 ;
505
+ }
506
+ return 0 ;
507
+ }
508
+
509
+ static enum list_objects_filter_result process_subfilter (
510
+ struct repository * r ,
511
+ enum list_objects_filter_situation filter_situation ,
512
+ struct object * obj ,
513
+ const char * pathname ,
514
+ const char * filename ,
515
+ struct subfilter * sub )
516
+ {
517
+ enum list_objects_filter_result result ;
518
+
519
+ /*
520
+ * Check should_delegate before oidset_contains so that
521
+ * is_skipping_tree gets unset even when the object is marked as seen.
522
+ * As of this writing, no filter uses LOFR_MARK_SEEN on trees that also
523
+ * uses LOFR_SKIP_TREE, so the ordering is only theoretically
524
+ * important. Be cautious if you change the order of the below checks
525
+ * and more filters have been added!
526
+ */
527
+ if (!should_delegate (filter_situation , obj , sub ))
528
+ return LOFR_ZERO ;
529
+ if (oidset_contains (& sub -> seen , & obj -> oid ))
530
+ return LOFR_ZERO ;
531
+
532
+ result = list_objects_filter__filter_object (
533
+ r , filter_situation , obj , pathname , filename , sub -> filter );
534
+
535
+ if (result & LOFR_MARK_SEEN )
536
+ oidset_insert (& sub -> seen , & obj -> oid );
537
+
538
+ if (result & LOFR_SKIP_TREE ) {
539
+ sub -> is_skipping_tree = 1 ;
540
+ sub -> skip_tree = obj -> oid ;
541
+ }
542
+
543
+ return result ;
544
+ }
545
+
546
+ static enum list_objects_filter_result filter_combine (
547
+ struct repository * r ,
548
+ enum list_objects_filter_situation filter_situation ,
549
+ struct object * obj ,
550
+ const char * pathname ,
551
+ const char * filename ,
552
+ struct oidset * omits ,
553
+ void * filter_data )
554
+ {
555
+ struct combine_filter_data * d = filter_data ;
556
+ enum list_objects_filter_result combined_result =
557
+ LOFR_DO_SHOW | LOFR_MARK_SEEN | LOFR_SKIP_TREE ;
558
+ size_t sub ;
559
+
560
+ for (sub = 0 ; sub < d -> nr ; sub ++ ) {
561
+ enum list_objects_filter_result sub_result = process_subfilter (
562
+ r , filter_situation , obj , pathname , filename ,
563
+ & d -> sub [sub ]);
564
+ if (!(sub_result & LOFR_DO_SHOW ))
565
+ combined_result &= ~LOFR_DO_SHOW ;
566
+ if (!(sub_result & LOFR_MARK_SEEN ))
567
+ combined_result &= ~LOFR_MARK_SEEN ;
568
+ if (!d -> sub [sub ].is_skipping_tree )
569
+ combined_result &= ~LOFR_SKIP_TREE ;
570
+ }
571
+
572
+ return combined_result ;
573
+ }
574
+
575
+ static void filter_combine__free (void * filter_data )
576
+ {
577
+ struct combine_filter_data * d = filter_data ;
578
+ size_t sub ;
579
+ for (sub = 0 ; sub < d -> nr ; sub ++ ) {
580
+ list_objects_filter__free (d -> sub [sub ].filter );
581
+ oidset_clear (& d -> sub [sub ].seen );
582
+ if (d -> sub [sub ].omits .set .size )
583
+ BUG ("expected oidset to be cleared already" );
584
+ }
585
+ free (d -> sub );
586
+ }
587
+
588
+ static void add_all (struct oidset * dest , struct oidset * src ) {
589
+ struct oidset_iter iter ;
590
+ struct object_id * src_oid ;
591
+
592
+ oidset_iter_init (src , & iter );
593
+ while ((src_oid = oidset_iter_next (& iter )) != NULL )
594
+ oidset_insert (dest , src_oid );
595
+ }
596
+
597
+ static void filter_combine__finalize_omits (
598
+ struct oidset * omits ,
599
+ void * filter_data )
600
+ {
601
+ struct combine_filter_data * d = filter_data ;
602
+ size_t sub ;
603
+
604
+ for (sub = 0 ; sub < d -> nr ; sub ++ ) {
605
+ add_all (omits , & d -> sub [sub ].omits );
606
+ oidset_clear (& d -> sub [sub ].omits );
607
+ }
608
+ }
609
+
610
+ static void filter_combine__init (
611
+ struct list_objects_filter_options * filter_options ,
612
+ struct filter * filter )
613
+ {
614
+ struct combine_filter_data * d = xcalloc (1 , sizeof (* d ));
615
+ size_t sub ;
616
+
617
+ d -> nr = filter_options -> sub_nr ;
618
+ d -> sub = xcalloc (d -> nr , sizeof (* d -> sub ));
619
+ for (sub = 0 ; sub < d -> nr ; sub ++ )
620
+ d -> sub [sub ].filter = list_objects_filter__init (
621
+ filter -> omits ? & d -> sub [sub ].omits : NULL ,
622
+ & filter_options -> sub [sub ]);
623
+
624
+ filter -> filter_data = d ;
625
+ filter -> filter_object_fn = filter_combine ;
626
+ filter -> free_fn = filter_combine__free ;
627
+ filter -> finalize_omits_fn = filter_combine__finalize_omits ;
628
+ }
629
+
474
630
typedef void (* filter_init_fn )(
475
631
struct list_objects_filter_options * filter_options ,
476
632
struct filter * filter );
@@ -484,6 +640,7 @@ static filter_init_fn s_filters[] = {
484
640
filter_blobs_limit__init ,
485
641
filter_trees_depth__init ,
486
642
filter_sparse_oid__init ,
643
+ filter_combine__init ,
487
644
};
488
645
489
646
struct filter * list_objects_filter__init (
@@ -535,6 +692,8 @@ void list_objects_filter__free(struct filter *filter)
535
692
{
536
693
if (!filter )
537
694
return ;
695
+ if (filter -> finalize_omits_fn && filter -> omits )
696
+ filter -> finalize_omits_fn (filter -> omits , filter -> filter_data );
538
697
filter -> free_fn (filter -> filter_data );
539
698
free (filter );
540
699
}
0 commit comments