@@ -5,68 +5,84 @@ import (
5
5
"strings"
6
6
)
7
7
8
- type ReferenceFilter func (refname string ) bool
8
+ type ReferenceFilter interface {
9
+ Filter (refname string ) bool
10
+ }
9
11
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
12
17
}
13
18
14
- type Polarity uint8
19
+ type inverse struct {
20
+ f ReferenceFilter
21
+ }
15
22
16
- const (
17
- Include Polarity = iota
18
- Exclude
19
- )
23
+ func (f inverse ) Filter (refname string ) bool {
24
+ return ! f .f .Filter (refname )
25
+ }
20
26
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 )
31
33
}
32
34
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 }
39
44
}
40
45
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
48
48
}
49
49
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
52
54
}
53
55
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 )
56
58
}
57
59
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 }
65
67
}
68
+ return intersection {f1 , inverse {f2 }}
69
+
70
+ }
66
71
67
- return len (ief .filters ) == 0 || ief .filters [0 ].polarity == Exclude
72
+ func (_ exclude ) Inverted () Combiner {
73
+ return include {}
68
74
}
69
75
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
+
70
86
// PrefixFilter returns a `ReferenceFilter` that matches references
71
87
// whose names start with the specified `prefix`, which must match at
72
88
// a component boundary. For example,
@@ -77,16 +93,23 @@ func (ief *IncludeExcludeFilter) Filter(refname string) bool {
77
93
// * Prefix "refs/foo/" matches "refs/foo/bar" but not "refs/foo" or
78
94
// "refs/foobar".
79
95
func 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
84
98
}
99
+ return prefixFilter {prefix }
100
+ }
85
101
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 )
89
109
}
110
+
111
+ return strings .HasPrefix (refname , f .prefix ) &&
112
+ (len (refname ) == len (f .prefix ) || refname [len (f .prefix )] == '/' )
90
113
}
91
114
92
115
// RegexpFilter returns a `ReferenceFilter` that matches references
@@ -99,7 +122,13 @@ func RegexpFilter(pattern string) (ReferenceFilter, error) {
99
122
return nil , err
100
123
}
101
124
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 )
105
134
}
0 commit comments