@@ -5,68 +5,84 @@ import (
55 "strings"
66)
77
8- type ReferenceFilter func (refname string ) bool
8+ type ReferenceFilter interface {
9+ Filter (refname string ) bool
10+ }
911
10- func AllReferencesFilter (_ string ) bool {
11- return true
12+ // Combiner combines two `ReferenceFilter`s into one compound one.
13+ // `f1` is allowed to be `nil`.
14+ type Combiner interface {
15+ Combine (f1 , f2 ReferenceFilter ) ReferenceFilter
16+ Inverted () Combiner
1217}
1318
14- type Polarity uint8
19+ type inverse struct {
20+ f ReferenceFilter
21+ }
1522
16- const (
17- Include Polarity = iota
18- Exclude
19- )
23+ func (f inverse ) Filter (refname string ) bool {
24+ return ! f .f .Filter (refname )
25+ }
2026
21- func (p Polarity ) Inverted () Polarity {
22- switch p {
23- case Include :
24- return Exclude
25- case Exclude :
26- return Include
27- default :
28- // This shouldn't happen:
29- return Exclude
30- }
27+ type intersection struct {
28+ f1 , f2 ReferenceFilter
29+ }
30+
31+ func (f intersection ) Filter (refname string ) bool {
32+ return f .f1 .Filter (refname ) && f .f2 .Filter (refname )
3133}
3234
33- // polarizedFilter is a filter that might match, in which case it
34- // includes or excludes the reference (according to its polarity). If
35- // it doesn't match, then it doesn't say anything about the reference.
36- type polarizedFilter struct {
37- polarity Polarity
38- filter ReferenceFilter
35+ // Include is a Combiner that includes the references matched by `f2`.
36+ // If `f1` is `nil`, it is treated as including nothing.
37+ type include struct {}
38+
39+ func (_ include ) Combine (f1 , f2 ReferenceFilter ) ReferenceFilter {
40+ if f1 == nil {
41+ return f2
42+ }
43+ return union {f1 , f2 }
3944}
4045
41- // IncludeExcludeFilter is a filter based on a bunch of
42- // `polarizedFilter`s. The last one that matches a reference wins. If
43- // none match, then the result is based on the polarity of the first
44- // polarizedFilter: if it is `Include`, then return `false`; if it is
45- // `Exclude`, then return `true`.
46- type IncludeExcludeFilter struct {
47- filters []polarizedFilter
46+ func (_ include ) Inverted () Combiner {
47+ return Exclude
4848}
4949
50- func (ief * IncludeExcludeFilter ) Include (f ReferenceFilter ) {
51- ief .filters = append (ief .filters , polarizedFilter {Include , f })
50+ var Include include
51+
52+ type union struct {
53+ f1 , f2 ReferenceFilter
5254}
5355
54- func (ief * IncludeExcludeFilter ) Exclude ( f ReferenceFilter ) {
55- ief . filters = append ( ief . filters , polarizedFilter { Exclude , f } )
56+ func (f union ) Filter ( refname string ) bool {
57+ return f . f1 . Filter ( refname ) || f . f2 . Filter ( refname )
5658}
5759
58- func ( ief * IncludeExcludeFilter ) Filter ( refname string ) bool {
59- for i := len ( ief . filters ); i > 0 ; i -- {
60- f := ief . filters [ i - 1 ]
61- if ! f . filter ( refname ) {
62- continue
63- }
64- return f . polarity == Include
60+ // Exclude is a Combiner that excludes the references matched by `f2`.
61+ // If `f1` is `nil`, it is treated as including everything.
62+ type exclude struct {}
63+
64+ func ( _ exclude ) Combine ( f1 , f2 ReferenceFilter ) ReferenceFilter {
65+ if f1 == nil {
66+ return inverse { f2 }
6567 }
68+ return intersection {f1 , inverse {f2 }}
69+
70+ }
6671
67- return len (ief .filters ) == 0 || ief .filters [0 ].polarity == Exclude
72+ func (_ exclude ) Inverted () Combiner {
73+ return include {}
6874}
6975
76+ var Exclude exclude
77+
78+ type allReferencesFilter struct {}
79+
80+ func (_ allReferencesFilter ) Filter (_ string ) bool {
81+ return true
82+ }
83+
84+ var AllReferencesFilter allReferencesFilter
85+
7086// PrefixFilter returns a `ReferenceFilter` that matches references
7187// whose names start with the specified `prefix`, which must match at
7288// a component boundary. For example,
@@ -77,16 +93,23 @@ func (ief *IncludeExcludeFilter) Filter(refname string) bool {
7793// * Prefix "refs/foo/" matches "refs/foo/bar" but not "refs/foo" or
7894// "refs/foobar".
7995func PrefixFilter (prefix string ) ReferenceFilter {
80- if strings .HasSuffix (prefix , "/" ) {
81- return func (refname string ) bool {
82- return strings .HasPrefix (refname , prefix )
83- }
96+ if prefix == "" {
97+ return AllReferencesFilter
8498 }
99+ return prefixFilter {prefix }
100+ }
85101
86- return func (refname string ) bool {
87- return strings .HasPrefix (refname , prefix ) &&
88- (len (refname ) == len (prefix ) || refname [len (prefix )] == '/' )
102+ type prefixFilter struct {
103+ prefix string
104+ }
105+
106+ func (f prefixFilter ) Filter (refname string ) bool {
107+ if strings .HasSuffix (f .prefix , "/" ) {
108+ return strings .HasPrefix (refname , f .prefix )
89109 }
110+
111+ return strings .HasPrefix (refname , f .prefix ) &&
112+ (len (refname ) == len (f .prefix ) || refname [len (f .prefix )] == '/' )
90113}
91114
92115// RegexpFilter returns a `ReferenceFilter` that matches references
@@ -99,7 +122,13 @@ func RegexpFilter(pattern string) (ReferenceFilter, error) {
99122 return nil , err
100123 }
101124
102- return func (refname string ) bool {
103- return re .MatchString (refname )
104- }, nil
125+ return regexpFilter {re }, nil
126+ }
127+
128+ type regexpFilter struct {
129+ re * regexp.Regexp
130+ }
131+
132+ func (f regexpFilter ) Filter (refname string ) bool {
133+ return f .re .MatchString (refname )
105134}
0 commit comments