File: ref_filter.go

package info (click to toggle)
git-sizer 1.5.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 616 kB
  • sloc: sh: 100; makefile: 61
file content (134 lines) | stat: -rw-r--r-- 2,922 bytes parent folder | download
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)
}