@@ -7,6 +7,19 @@ import (
77 "github.com/github/git-sizer/sizes"
88)
99
10+ // filterGroupValue handles `--refgroup=REFGROUP` options, which
11+ // affect the top-level filter. These are a little bit tricky, because
12+ // the references matched by a refgroup depend on its parents (because
13+ // if the parents don't allow the reference, it won't even get tested
14+ // by the regroup's own filter) and also its children (because if the
15+ // refgroup doesn't have its own filter, then it is defined to be the
16+ // union of its children). Meanwhile, when testing parents, we
17+ // shouldn't test the top-level group, because that's what we are
18+ // trying to affect.
19+ //
20+ // The filtering itself is implemented using a `refGroupFilter`, which
21+ // contains a pointer to a `refGroup` and uses it (including its
22+ // `parent` and `subgroups` to figure out what should be allowed.
1023type filterGroupValue struct {
1124 filter * git.ReferenceFilter
1225 groups map [sizes.RefGroupSymbol ]* refGroup
@@ -21,7 +34,7 @@ func (v *filterGroupValue) Set(symbolString string) error {
2134 return fmt .Errorf ("refgroup '%s' is not defined" , symbol )
2235 }
2336
24- * v .filter = git .Include .Combine (* v .filter , refGroup . filter )
37+ * v .filter = git .Include .Combine (* v .filter , refGroupFilter { refGroup } )
2538
2639 return nil
2740}
@@ -37,3 +50,46 @@ func (v *filterGroupValue) String() string {
3750func (v * filterGroupValue ) Type () string {
3851 return "name"
3952}
53+
54+ // refGroupFilter is a filter based on what would be allowed through
55+ // by a particular refGroup. This is used as part of a top-level
56+ // filter, so it ignores what the top-level filter would say.
57+ type refGroupFilter struct {
58+ refGroup * refGroup
59+ }
60+
61+ func (f refGroupFilter ) Filter (refname string ) bool {
62+ return refGroupPasses (f .refGroup .parent , refname ) &&
63+ refGroupMatches (f .refGroup , refname )
64+ }
65+
66+ // refGroupMatches retruns true iff `rg` would allow `refname`
67+ // through, not considering its parents. If `rg` doesn't have its own
68+ // filter, this consults its children.
69+ func refGroupMatches (rg * refGroup , refname string ) bool {
70+ if rg .filter != nil {
71+ return rg .filter .Filter (refname )
72+ }
73+
74+ for _ , sg := range rg .subgroups {
75+ if refGroupMatches (sg , refname ) {
76+ return true
77+ }
78+ }
79+
80+ return false
81+ }
82+
83+ // refGroupPasses returns true iff `rg` and the parents of `rg` (not
84+ // including the top-level group) would allow `refname` through. This
85+ // does not consider children of `rg`, which we would still need to
86+ // consult if `rg` doesn't have a filter of its own.
87+ func refGroupPasses (rg * refGroup , refname string ) bool {
88+ if rg .Symbol == "" {
89+ return true
90+ }
91+ if ! refGroupPasses (rg .parent , refname ) {
92+ return false
93+ }
94+ return rg .filter == nil || rg .filter .Filter (refname )
95+ }
0 commit comments