Skip to content

Commit 1955ee0

Browse files
committed
RefGroupBuilder: use the refgroups defined in gitconfig to group refs
1 parent a909729 commit 1955ee0

3 files changed

Lines changed: 331 additions & 28 deletions

File tree

git-sizer.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,16 @@ func mainImplementation(args []string) error {
156156
flags.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to file")
157157
flags.MarkHidden("cpuprofile")
158158

159-
var rgb refopts.RefGroupBuilder
160159
var configger refopts.Configger
161160
if repo != nil {
162161
configger = repo
163162
}
163+
164+
rgb, err := refopts.NewRefGroupBuilder(configger)
165+
if err != nil {
166+
return err
167+
}
168+
164169
rgb.AddRefopts(flags, configger)
165170

166171
flags.SortFlags = false

internal/refopts/ref_group.go

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package refopts
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/github/git-sizer/git"
7+
"github.com/github/git-sizer/sizes"
8+
)
9+
10+
// refGroup represents one reference group and also its relationship
11+
// to its parent group and any subgroups.. Note that reference groups
12+
// don't intrinsically have anything to do with the layout of the
13+
// reference namespace, but they will often be used that way.
14+
type refGroup struct {
15+
sizes.RefGroup
16+
17+
// filter is the filter for just this reference group. Filters
18+
// for any parent groups must also be applied.
19+
filter git.ReferenceFilter
20+
21+
parent *refGroup
22+
23+
// subgroups are the `refGroup` instances representing any
24+
// direct subgroups.
25+
subgroups []*refGroup
26+
27+
// otherRefGroup, if set, is the refGroup for tallying
28+
// references that match `filter` but don't match any of the
29+
// subgroups.
30+
otherRefGroup *sizes.RefGroup
31+
}
32+
33+
func (rg *refGroup) collectSymbols(refname string) (bool, []sizes.RefGroupSymbol) {
34+
walk := false
35+
var symbols []sizes.RefGroupSymbol
36+
37+
if rg.filter == nil {
38+
// The tree doesn't have its own filter. Consider it matched
39+
// iff at least one subtree matches it.
40+
41+
for _, sg := range rg.subgroups {
42+
w, ss := sg.collectSymbols(refname)
43+
if w {
44+
walk = true
45+
}
46+
if len(ss) > 0 && len(symbols) == 0 {
47+
symbols = append(symbols, rg.Symbol)
48+
}
49+
symbols = append(symbols, ss...)
50+
}
51+
} else {
52+
// The tree has its own filter. If it doesn't match the
53+
// reference, then the subtrees don't even get a chance to
54+
// try.
55+
if !rg.filter.Filter(refname) {
56+
return false, nil
57+
}
58+
59+
walk = true
60+
symbols = append(symbols, rg.Symbol)
61+
62+
for _, sg := range rg.subgroups {
63+
_, ss := sg.collectSymbols(refname)
64+
symbols = append(symbols, ss...)
65+
}
66+
67+
// References that match the tree filter but no subtree
68+
// filters are counted as "other":
69+
if rg.otherRefGroup != nil && len(symbols) == 1 {
70+
symbols = append(symbols, rg.otherRefGroup.Symbol)
71+
}
72+
}
73+
74+
return walk, symbols
75+
}
76+
77+
// augmentFromConfig augments `rg` based on configuration in the
78+
// gitconfig and returns the result. It is not considered an error if
79+
// there are no usable config entries for the filter.
80+
func (rg *refGroup) augmentFromConfig(configger Configger) error {
81+
config, err := configger.Config(fmt.Sprintf("refgroup.%s", rg.Symbol))
82+
if err != nil {
83+
return err
84+
}
85+
86+
for _, entry := range config.Entries {
87+
switch entry.Key {
88+
case "name":
89+
rg.Name = entry.Value
90+
case "include":
91+
rg.filter = git.Include.Combine(
92+
rg.filter, git.PrefixFilter(entry.Value),
93+
)
94+
case "includeregexp":
95+
f, err := git.RegexpFilter(entry.Value)
96+
if err != nil {
97+
return fmt.Errorf(
98+
"invalid regular expression for '%s': %w",
99+
config.FullKey(entry.Key), err,
100+
)
101+
}
102+
rg.filter = git.Include.Combine(rg.filter, f)
103+
case "exclude":
104+
rg.filter = git.Exclude.Combine(
105+
rg.filter, git.PrefixFilter(entry.Value),
106+
)
107+
case "excluderegexp":
108+
f, err := git.RegexpFilter(entry.Value)
109+
if err != nil {
110+
return fmt.Errorf(
111+
"invalid regular expression for '%s': %w",
112+
config.FullKey(entry.Key), err,
113+
)
114+
}
115+
rg.filter = git.Exclude.Combine(rg.filter, f)
116+
default:
117+
// Ignore unrecognized keys.
118+
}
119+
}
120+
121+
return nil
122+
}

0 commit comments

Comments
 (0)