22
22
#include "../repo-settings.h"
23
23
#include "../setup.h"
24
24
#include "../strmap.h"
25
+ #include "../trace2.h"
25
26
#include "parse.h"
26
27
#include "refs-internal.h"
27
28
@@ -451,10 +452,81 @@ struct reftable_ref_iterator {
451
452
452
453
const char * prefix ;
453
454
size_t prefix_len ;
455
+ char * * exclude_patterns ;
456
+ size_t exclude_patterns_index ;
457
+ size_t exclude_patterns_strlen ;
454
458
unsigned int flags ;
455
459
int err ;
456
460
};
457
461
462
+ /*
463
+ * Handle exclude patterns. Returns either `1`, which tells the caller that the
464
+ * current reference shall not be shown. Or `0`, which indicates that it should
465
+ * be shown.
466
+ */
467
+ static int should_exclude_current_ref (struct reftable_ref_iterator * iter )
468
+ {
469
+ while (iter -> exclude_patterns [iter -> exclude_patterns_index ]) {
470
+ const char * pattern = iter -> exclude_patterns [iter -> exclude_patterns_index ];
471
+ char * ref_after_pattern ;
472
+ int cmp ;
473
+
474
+ /*
475
+ * Lazily cache the pattern length so that we don't have to
476
+ * recompute it every time this function is called.
477
+ */
478
+ if (!iter -> exclude_patterns_strlen )
479
+ iter -> exclude_patterns_strlen = strlen (pattern );
480
+
481
+ /*
482
+ * When the reference name is lexicographically bigger than the
483
+ * current exclude pattern we know that it won't ever match any
484
+ * of the following references, either. We thus advance to the
485
+ * next pattern and re-check whether it matches.
486
+ *
487
+ * Otherwise, if it's smaller, then we do not have a match and
488
+ * thus want to show the current reference.
489
+ */
490
+ cmp = strncmp (iter -> ref .refname , pattern ,
491
+ iter -> exclude_patterns_strlen );
492
+ if (cmp > 0 ) {
493
+ iter -> exclude_patterns_index ++ ;
494
+ iter -> exclude_patterns_strlen = 0 ;
495
+ continue ;
496
+ }
497
+ if (cmp < 0 )
498
+ return 0 ;
499
+
500
+ /*
501
+ * The reference shares a prefix with the exclude pattern and
502
+ * shall thus be omitted. We skip all references that match the
503
+ * pattern by seeking to the first reference after the block of
504
+ * matches.
505
+ *
506
+ * This is done by appending the highest possible character to
507
+ * the pattern. Consequently, all references that have the
508
+ * pattern as prefix and whose suffix starts with anything in
509
+ * the range [0x00, 0xfe] are skipped. And given that 0xff is a
510
+ * non-printable character that shouldn't ever be in a ref name,
511
+ * we'd not yield any such record, either.
512
+ *
513
+ * Note that the seeked-to reference may also be excluded. This
514
+ * is not handled here though, but the caller is expected to
515
+ * loop and re-verify the next reference for us.
516
+ */
517
+ ref_after_pattern = xstrfmt ("%s%c" , pattern , 0xff );
518
+ iter -> err = reftable_iterator_seek_ref (& iter -> iter , ref_after_pattern );
519
+ iter -> exclude_patterns_index ++ ;
520
+ iter -> exclude_patterns_strlen = 0 ;
521
+ trace2_counter_add (TRACE2_COUNTER_ID_REFTABLE_RESEEKS , 1 );
522
+
523
+ free (ref_after_pattern );
524
+ return 1 ;
525
+ }
526
+
527
+ return 0 ;
528
+ }
529
+
458
530
static int reftable_ref_iterator_advance (struct ref_iterator * ref_iterator )
459
531
{
460
532
struct reftable_ref_iterator * iter =
@@ -485,6 +557,9 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
485
557
break ;
486
558
}
487
559
560
+ if (iter -> exclude_patterns && should_exclude_current_ref (iter ))
561
+ continue ;
562
+
488
563
if (iter -> flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
489
564
parse_worktree_ref (iter -> ref .refname , NULL , NULL , NULL ) !=
490
565
REF_WORKTREE_CURRENT )
@@ -574,6 +649,11 @@ static int reftable_ref_iterator_abort(struct ref_iterator *ref_iterator)
574
649
(struct reftable_ref_iterator * )ref_iterator ;
575
650
reftable_ref_record_release (& iter -> ref );
576
651
reftable_iterator_destroy (& iter -> iter );
652
+ if (iter -> exclude_patterns ) {
653
+ for (size_t i = 0 ; iter -> exclude_patterns [i ]; i ++ )
654
+ free (iter -> exclude_patterns [i ]);
655
+ free (iter -> exclude_patterns );
656
+ }
577
657
free (iter );
578
658
return ITER_DONE ;
579
659
}
@@ -584,9 +664,53 @@ static struct ref_iterator_vtable reftable_ref_iterator_vtable = {
584
664
.abort = reftable_ref_iterator_abort
585
665
};
586
666
667
+ static int qsort_strcmp (const void * va , const void * vb )
668
+ {
669
+ const char * a = * (const char * * )va ;
670
+ const char * b = * (const char * * )vb ;
671
+ return strcmp (a , b );
672
+ }
673
+
674
+ static char * * filter_exclude_patterns (const char * * exclude_patterns )
675
+ {
676
+ size_t filtered_size = 0 , filtered_alloc = 0 ;
677
+ char * * filtered = NULL ;
678
+
679
+ if (!exclude_patterns )
680
+ return NULL ;
681
+
682
+ for (size_t i = 0 ; ; i ++ ) {
683
+ const char * exclude_pattern = exclude_patterns [i ];
684
+ int has_glob = 0 ;
685
+
686
+ if (!exclude_pattern )
687
+ break ;
688
+
689
+ for (const char * p = exclude_pattern ; * p ; p ++ ) {
690
+ has_glob = is_glob_special (* p );
691
+ if (has_glob )
692
+ break ;
693
+ }
694
+ if (has_glob )
695
+ continue ;
696
+
697
+ ALLOC_GROW (filtered , filtered_size + 1 , filtered_alloc );
698
+ filtered [filtered_size ++ ] = xstrdup (exclude_pattern );
699
+ }
700
+
701
+ if (filtered_size ) {
702
+ QSORT (filtered , filtered_size , qsort_strcmp );
703
+ ALLOC_GROW (filtered , filtered_size + 1 , filtered_alloc );
704
+ filtered [filtered_size ++ ] = NULL ;
705
+ }
706
+
707
+ return filtered ;
708
+ }
709
+
587
710
static struct reftable_ref_iterator * ref_iterator_for_stack (struct reftable_ref_store * refs ,
588
711
struct reftable_stack * stack ,
589
712
const char * prefix ,
713
+ const char * * exclude_patterns ,
590
714
int flags )
591
715
{
592
716
struct reftable_ref_iterator * iter ;
@@ -599,6 +723,7 @@ static struct reftable_ref_iterator *ref_iterator_for_stack(struct reftable_ref_
599
723
iter -> base .oid = & iter -> oid ;
600
724
iter -> flags = flags ;
601
725
iter -> refs = refs ;
726
+ iter -> exclude_patterns = filter_exclude_patterns (exclude_patterns );
602
727
603
728
ret = refs -> err ;
604
729
if (ret )
@@ -620,7 +745,7 @@ static struct reftable_ref_iterator *ref_iterator_for_stack(struct reftable_ref_
620
745
621
746
static struct ref_iterator * reftable_be_iterator_begin (struct ref_store * ref_store ,
622
747
const char * prefix ,
623
- const char * * exclude_patterns UNUSED ,
748
+ const char * * exclude_patterns ,
624
749
unsigned int flags )
625
750
{
626
751
struct reftable_ref_iterator * main_iter , * worktree_iter ;
@@ -631,7 +756,8 @@ static struct ref_iterator *reftable_be_iterator_begin(struct ref_store *ref_sto
631
756
required_flags |= REF_STORE_ODB ;
632
757
refs = reftable_be_downcast (ref_store , required_flags , "ref_iterator_begin" );
633
758
634
- main_iter = ref_iterator_for_stack (refs , refs -> main_stack , prefix , flags );
759
+ main_iter = ref_iterator_for_stack (refs , refs -> main_stack , prefix ,
760
+ exclude_patterns , flags );
635
761
636
762
/*
637
763
* The worktree stack is only set when we're in an actual worktree
@@ -645,7 +771,8 @@ static struct ref_iterator *reftable_be_iterator_begin(struct ref_store *ref_sto
645
771
* Otherwise we merge both the common and the per-worktree refs into a
646
772
* single iterator.
647
773
*/
648
- worktree_iter = ref_iterator_for_stack (refs , refs -> worktree_stack , prefix , flags );
774
+ worktree_iter = ref_iterator_for_stack (refs , refs -> worktree_stack , prefix ,
775
+ exclude_patterns , flags );
649
776
return merge_ref_iterator_begin (& worktree_iter -> base , & main_iter -> base ,
650
777
ref_iterator_select , NULL );
651
778
}
0 commit comments