26
*/
27
#define FILTER_SHOWN_BUT_REVISIT (1<<21)
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
+
37
struct filter {
38
enum list_objects_filter_result (*filter_object_fn)(
39
struct repository *r,
44
struct oidset *omits,
45
void *filter_data);
46
47
+ /*
48
+ * Optional. If this function is supplied and the filter needs
49
+ * to collect omits, then this function is called once before
50
+ * free_fn is called.
51
+ *
52
+ * This is required because the following two conditions hold:
53
+ *
54
+ * a. A tree filter can add and remove objects as an object
55
+ * graph is traversed.
56
+ * b. A combine filter's omit set is the union of all its
57
+ * subfilters, which may include tree: filters.
58
+ *
59
+ * As such, the omits sets must be separate sets, and can only
60
+ * be unioned after the traversal is completed.
61
+ */
62
+ void (*finalize_omits_fn)(struct oidset *omits, void *filter_data);
63
+
64
void (*free_fn)(void *filter_data);
65
66
void *filter_data;
496
filter->free_fn = filter_sparse_free;
497
}
498
499
+/* A filter which only shows objects shown by all sub-filters. */
500
+struct combine_filter_data {
501
+ struct subfilter *sub;
502
+ size_t nr;
503
+};
504
+
505
+static enum list_objects_filter_result process_subfilter(
506
+ struct repository *r,
507
+ enum list_objects_filter_situation filter_situation,
508
+ struct object *obj,
509
+ const char *pathname,
510
+ const char *filename,
511
+ struct subfilter *sub)
512
+{
513
+ enum list_objects_filter_result result;
514
+
515
+ /*
516
+ * Check and update is_skipping_tree before oidset_contains so
517
+ * that is_skipping_tree gets unset even when the object is
518
+ * marked as seen. As of this writing, no filter uses
519
+ * LOFR_MARK_SEEN on trees that also uses LOFR_SKIP_TREE, so the
520
+ * ordering is only theoretically important. Be cautious if you
521
+ * change the order of the below checks and more filters have
522
+ * been added!
523
+ */
524
+ if (sub->is_skipping_tree) {
525
+ if (filter_situation == LOFS_END_TREE &&
526
+ oideq(&obj->oid, &sub->skip_tree))
527
+ sub->is_skipping_tree = 0;
528
+ else
529
+ return LOFR_ZERO;
530
+ }
531
+ if (oidset_contains(&sub->seen, &obj->oid))
532
+ return LOFR_ZERO;
533
+
534
+ result = list_objects_filter__filter_object(
535
+ r, filter_situation, obj, pathname, filename, sub->filter);
536
+
537
+ if (result & LOFR_MARK_SEEN)
538
+ oidset_insert(&sub->seen, &obj->oid);
539
+
540
+ if (result & LOFR_SKIP_TREE) {
541
+ sub->is_skipping_tree = 1;
542
+ sub->skip_tree = obj->oid;
543
+ }
544
+
545
+ return result;
546
+}
547
+
548
+static enum list_objects_filter_result filter_combine(
549
+ struct repository *r,
550
+ enum list_objects_filter_situation filter_situation,
551
+ struct object *obj,
552
+ const char *pathname,
553
+ const char *filename,
554
+ struct oidset *omits,
555
+ void *filter_data)
556
+{
557
+ struct combine_filter_data *d = filter_data;
558
+ enum list_objects_filter_result combined_result =
559
+ LOFR_DO_SHOW | LOFR_MARK_SEEN | LOFR_SKIP_TREE;
560
+ size_t sub;
561
+
562
+ for (sub = 0; sub < d->nr; sub++) {
563
+ enum list_objects_filter_result sub_result = process_subfilter(
564
+ r, filter_situation, obj, pathname, filename,
565
+ &d->sub[sub]);
566
+ if (!(sub_result & LOFR_DO_SHOW))
567
+ combined_result &= ~LOFR_DO_SHOW;
568
+ if (!(sub_result & LOFR_MARK_SEEN))
569
+ combined_result &= ~LOFR_MARK_SEEN;
570
+ if (!d->sub[sub].is_skipping_tree)
571
+ combined_result &= ~LOFR_SKIP_TREE;
572
+ }
573
+
574
+ return combined_result;
575
+}
576
+
577
+static void filter_combine__free(void *filter_data)
578
+{
579
+ struct combine_filter_data *d = filter_data;
580
+ size_t sub;
581
+ for (sub = 0; sub < d->nr; sub++) {
582
+ list_objects_filter__free(d->sub[sub].filter);
583
+ oidset_clear(&d->sub[sub].seen);
584
+ if (d->sub[sub].omits.set.size)
585
+ BUG("expected oidset to be cleared already");
586
+ }
587
+ free(d->sub);
588
+}
589
+
590
+static void add_all(struct oidset *dest, struct oidset *src) {
591
+ struct oidset_iter iter;
592
+ struct object_id *src_oid;
593
+
594
+ oidset_iter_init(src, &iter);
595
+ while ((src_oid = oidset_iter_next(&iter)) != NULL)
596
+ oidset_insert(dest, src_oid);
597
+}
598
+
599
+static void filter_combine__finalize_omits(
600
+ struct oidset *omits,
601
+ void *filter_data)
602
+{
603
+ struct combine_filter_data *d = filter_data;
604
+ size_t sub;
605
+
606
+ for (sub = 0; sub < d->nr; sub++) {
607
+ add_all(omits, &d->sub[sub].omits);
608
+ oidset_clear(&d->sub[sub].omits);
609
+ }
610
+}
611
+
612
+static void filter_combine__init(
613
+ struct list_objects_filter_options *filter_options,
614
+ struct filter* filter)
615
+{
616
+ struct combine_filter_data *d = xcalloc(1, sizeof(*d));
617
+ size_t sub;
618
+
619
+ d->nr = filter_options->sub_nr;
620
+ d->sub = xcalloc(d->nr, sizeof(*d->sub));
621
+ for (sub = 0; sub < d->nr; sub++)
622
+ d->sub[sub].filter = list_objects_filter__init(
623
+ filter->omits ? &d->sub[sub].omits : NULL,
624
+ &filter_options->sub[sub]);
625
+
626
+ filter->filter_data = d;
627
+ filter->filter_object_fn = filter_combine;
628
+ filter->free_fn = filter_combine__free;
629
+ filter->finalize_omits_fn = filter_combine__finalize_omits;
630
+}
631
+
632
typedef void (*filter_init_fn)(
633
struct list_objects_filter_options *filter_options,
634
struct filter *filter);
642
filter_blobs_limit__init,
643
filter_trees_depth__init,
644
filter_sparse_oid__init,
645
+ filter_combine__init,
646
};
647
648
struct filter *list_objects_filter__init(
695
{
696
if (!filter)
697
return;
698
+ if (filter->finalize_omits_fn && filter->omits)
699
+ filter->finalize_omits_fn(filter->omits, filter->filter_data);
700
filter->free_fn(filter->filter_data);
701
free(filter);
702
}