1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
package git
import (
"regexp"
"strings"
)
type ReferenceFilter interface {
Filter(refname string) bool
}
// Combiner combines two `ReferenceFilter`s into one compound one.
// `f1` is allowed to be `nil`.
type Combiner interface {
Combine(f1, f2 ReferenceFilter) ReferenceFilter
Inverted() Combiner
}
type inverse struct {
f ReferenceFilter
}
func (f inverse) Filter(refname string) bool {
return !f.f.Filter(refname)
}
type intersection struct {
f1, f2 ReferenceFilter
}
func (f intersection) Filter(refname string) bool {
return f.f1.Filter(refname) && f.f2.Filter(refname)
}
// Include is a Combiner that includes the references matched by `f2`.
// If `f1` is `nil`, it is treated as including nothing.
type include struct{}
func (_ include) Combine(f1, f2 ReferenceFilter) ReferenceFilter {
if f1 == nil {
return f2
}
return union{f1, f2}
}
func (_ include) Inverted() Combiner {
return Exclude
}
var Include include
type union struct {
f1, f2 ReferenceFilter
}
func (f union) Filter(refname string) bool {
return f.f1.Filter(refname) || f.f2.Filter(refname)
}
// Exclude is a Combiner that excludes the references matched by `f2`.
// If `f1` is `nil`, it is treated as including everything.
type exclude struct{}
func (_ exclude) Combine(f1, f2 ReferenceFilter) ReferenceFilter {
if f1 == nil {
return inverse{f2}
}
return intersection{f1, inverse{f2}}
}
func (_ exclude) Inverted() Combiner {
return include{}
}
var Exclude exclude
type allReferencesFilter struct{}
func (_ allReferencesFilter) Filter(_ string) bool {
return true
}
var AllReferencesFilter allReferencesFilter
// PrefixFilter returns a `ReferenceFilter` that matches references
// whose names start with the specified `prefix`, which must match at
// a component boundary. For example,
//
// * Prefix "refs/foo" matches "refs/foo" and "refs/foo/bar" but not
// "refs/foobar".
//
// * Prefix "refs/foo/" matches "refs/foo/bar" but not "refs/foo" or
// "refs/foobar".
func PrefixFilter(prefix string) ReferenceFilter {
if prefix == "" {
return AllReferencesFilter
}
return prefixFilter{prefix}
}
type prefixFilter struct {
prefix string
}
func (f prefixFilter) Filter(refname string) bool {
if strings.HasSuffix(f.prefix, "/") {
return strings.HasPrefix(refname, f.prefix)
}
return strings.HasPrefix(refname, f.prefix) &&
(len(refname) == len(f.prefix) || refname[len(f.prefix)] == '/')
}
// RegexpFilter returns a `ReferenceFilter` that matches references
// whose names match the specified `prefix`, which must match the
// whole reference name.
func RegexpFilter(pattern string) (ReferenceFilter, error) {
pattern = "^" + pattern + "$"
re, err := regexp.Compile(pattern)
if err != nil {
return nil, err
}
return regexpFilter{re}, nil
}
type regexpFilter struct {
re *regexp.Regexp
}
func (f regexpFilter) Filter(refname string) bool {
return f.re.MatchString(refname)
}
|