@@ -16,60 +16,200 @@ import (
16
16
"github.com/spf13/pflag"
17
17
)
18
18
19
+ const Usage = `usage: git-sizer [OPTS]
20
+
21
+ -v, --verbose report all statistics, whether concerning or not
22
+ --threshold THRESHOLD minimum level of concern (i.e., number of stars)
23
+ that should be reported. Default:
24
+ '--threshold=1'.
25
+ --critical only report critical statistics
26
+ --names=[none|hash|full] display names of large objects in the specified
27
+ style: 'none' (omit footnotes entirely), 'hash'
28
+ (show only the SHA-1s of objects), or 'full'
29
+ (show full names). Default is '--names=full'.
30
+ -j, --json output results in JSON format
31
+ --json-version=[1|2] choose which JSON format version to output.
32
+ Default: --json-version=1.
33
+ --[no-]progress report (don't report) progress to stderr.
34
+ --version only report the git-sizer version number
35
+
36
+ Reference selection:
37
+
38
+ By default, git-sizer processes all Git objects that are reachable from any
39
+ reference. The following options can be used to limit which references to
40
+ include. The last rule matching a reference determines whether that reference
41
+ is processed:
42
+
43
+ --branches process branches
44
+ --tags process tags
45
+ --remotes process remote refs
46
+ --include PREFIX process references with the specified PREFIX
47
+ (e.g., '--include=refs/remotes/origin')
48
+ --include-regexp REGEXP process references matching the specified
49
+ regular expression (e.g.,
50
+ '--include-regexp=refs/tags/release-.*')
51
+ --exclude PREFIX don't process references with the specified
52
+ PREFIX (e.g., '--exclude=refs/notes')
53
+ --exclude-regexp REGEXP don't process references matching the specified
54
+ regular expression
55
+ --show-refs show which refs are being included/excluded
56
+
57
+ Prefixes must match at a boundary; for example 'refs/foo' matches
58
+ 'refs/foo' and 'refs/foo/bar' but not 'refs/foobar'. Regular
59
+ expression patterns must match the full reference name.
60
+
61
+ `
62
+
19
63
var ReleaseVersion string
20
64
var BuildVersion string
21
65
22
66
type NegatedBoolValue struct {
23
67
value * bool
24
68
}
25
69
26
- func (b * NegatedBoolValue ) Set (s string ) error {
27
- v , err := strconv .ParseBool (s )
28
- * b .value = ! v
70
+ func (v * NegatedBoolValue ) Set (s string ) error {
71
+ b , err := strconv .ParseBool (s )
72
+ * v .value = ! b
29
73
return err
30
74
}
31
75
32
- func (b * NegatedBoolValue ) Get () interface {} {
33
- return ! * b .value
76
+ func (v * NegatedBoolValue ) Get () interface {} {
77
+ return ! * v .value
34
78
}
35
79
36
- func (b * NegatedBoolValue ) String () string {
37
- if b == nil || b .value == nil {
80
+ func (v * NegatedBoolValue ) String () string {
81
+ if v == nil || v .value == nil {
38
82
return "true"
39
83
} else {
40
- return strconv .FormatBool (! * b .value )
84
+ return strconv .FormatBool (! * v .value )
41
85
}
42
86
}
43
87
44
88
func (v * NegatedBoolValue ) Type () string {
45
89
return "bool"
46
90
}
47
91
92
+ type filterValue struct {
93
+ filter * git.IncludeExcludeFilter
94
+ polarity git.Polarity
95
+ pattern string
96
+ regexp bool
97
+ }
98
+
99
+ func (v * filterValue ) Set (s string ) error {
100
+ var polarity git.Polarity
101
+ var filter git.ReferenceFilter
102
+
103
+ if v .regexp {
104
+ polarity = v .polarity
105
+ var err error
106
+ filter , err = git .RegexpFilter (s )
107
+ if err != nil {
108
+ return fmt .Errorf ("invalid regexp: %q" , s )
109
+ }
110
+ } else if v .pattern == "" {
111
+ polarity = v .polarity
112
+ filter = git .PrefixFilter (s )
113
+ } else {
114
+ // Allow a boolean value to alter the polarity:
115
+ b , err := strconv .ParseBool (s )
116
+ if err != nil {
117
+ return err
118
+ }
119
+ if b {
120
+ polarity = git .Include
121
+ } else {
122
+ polarity = git .Exclude
123
+ }
124
+ filter = git .PrefixFilter (v .pattern )
125
+ }
126
+
127
+ switch polarity {
128
+ case git .Include :
129
+ v .filter .Include (filter )
130
+ case git .Exclude :
131
+ v .filter .Exclude (filter )
132
+ }
133
+
134
+ return nil
135
+ }
136
+
137
+ func (v * filterValue ) Get () interface {} {
138
+ return nil
139
+ }
140
+
141
+ func (v * filterValue ) String () string {
142
+ return ""
143
+ }
144
+
145
+ func (v * filterValue ) Type () string {
146
+ if v .regexp {
147
+ return "regexp"
148
+ } else if v .pattern == "" {
149
+ return "prefix"
150
+ } else {
151
+ return ""
152
+ }
153
+ }
154
+
48
155
func main () {
49
- err := mainImplementation ()
156
+ err := mainImplementation (os . Args [ 1 :] )
50
157
if err != nil {
51
158
fmt .Fprintf (os .Stderr , "error: %s\n " , err )
52
159
os .Exit (1 )
53
160
}
54
161
}
55
162
56
- func mainImplementation () error {
57
- var processBranches bool
58
- var processTags bool
59
- var processRemotes bool
163
+ func mainImplementation (args []string ) error {
60
164
var nameStyle sizes.NameStyle = sizes .NameStyleFull
61
165
var cpuprofile string
62
166
var jsonOutput bool
63
167
var jsonVersion uint
64
168
var threshold sizes.Threshold = 1
65
169
var progress bool
66
170
var version bool
171
+ var filter git.IncludeExcludeFilter
172
+ var showRefs bool
173
+
174
+ flags := pflag .NewFlagSet ("git-sizer" , pflag .ContinueOnError )
175
+ flags .Usage = func () {
176
+ fmt .Print (Usage )
177
+ }
178
+
179
+ flags .Var (
180
+ & filterValue {& filter , git .Include , "" , false }, "include" ,
181
+ "include specified references" ,
182
+ )
183
+ flags .Var (
184
+ & filterValue {& filter , git .Include , "" , true }, "include-regexp" ,
185
+ "include references matching the specified regular expression" ,
186
+ )
187
+ flags .Var (
188
+ & filterValue {& filter , git .Exclude , "" , false }, "exclude" ,
189
+ "exclude specified references" ,
190
+ )
191
+ flags .Var (
192
+ & filterValue {& filter , git .Exclude , "" , true }, "exclude-regexp" ,
193
+ "exclude references matching the specified regular expression" ,
194
+ )
67
195
68
- flags := pflag .NewFlagSet ("" , pflag .ContinueOnError )
196
+ flag := flags .VarPF (
197
+ & filterValue {& filter , git .Include , "refs/heads/" , false }, "branches" , "" ,
198
+ "process all branches" ,
199
+ )
200
+ flag .NoOptDefVal = "true"
201
+
202
+ flag = flags .VarPF (
203
+ & filterValue {& filter , git .Include , "refs/tags/" , false }, "tags" , "" ,
204
+ "process all tags" ,
205
+ )
206
+ flag .NoOptDefVal = "true"
69
207
70
- flags .BoolVar (& processBranches , "branches" , false , "process all branches" )
71
- flags .BoolVar (& processTags , "tags" , false , "process all tags" )
72
- flags .BoolVar (& processRemotes , "remotes" , false , "process all remote-tracking branches" )
208
+ flag = flags .VarPF (
209
+ & filterValue {& filter , git .Include , "refs/remotes/" , false }, "remotes" , "" ,
210
+ "process all remotes" ,
211
+ )
212
+ flag .NoOptDefVal = "true"
73
213
74
214
flags .VarP (
75
215
sizes .NewThresholdFlagValue (& threshold , 0 ),
@@ -105,6 +245,7 @@ func mainImplementation() error {
105
245
atty = false
106
246
}
107
247
flags .BoolVar (& progress , "progress" , atty , "report progress to stderr" )
248
+ flags .BoolVar (& showRefs , "show-refs" , false , "list the references being processed" )
108
249
flags .BoolVar (& version , "version" , false , "report the git-sizer version number" )
109
250
flags .Var (& NegatedBoolValue {& progress }, "no-progress" , "suppress progress output" )
110
251
flags .Lookup ("no-progress" ).NoOptDefVal = "true"
@@ -114,7 +255,7 @@ func mainImplementation() error {
114
255
115
256
flags .SortFlags = false
116
257
117
- err = flags .Parse (os . Args [ 1 :] )
258
+ err = flags .Parse (args )
118
259
if err != nil {
119
260
if err == pflag .ErrHelp {
120
261
return nil
@@ -144,9 +285,7 @@ func mainImplementation() error {
144
285
return nil
145
286
}
146
287
147
- args := flags .Args ()
148
-
149
- if len (args ) != 0 {
288
+ if len (flags .Args ()) != 0 {
150
289
return errors .New ("excess arguments" )
151
290
}
152
291
@@ -158,24 +297,23 @@ func mainImplementation() error {
158
297
159
298
var historySize sizes.HistorySize
160
299
161
- var filter git.ReferenceFilter
162
- if processBranches || processTags || processRemotes {
163
- var filters []git.ReferenceFilter
164
- if processBranches {
165
- filters = append (filters , git .BranchesFilter )
300
+ var refFilter git.ReferenceFilter = filter .Filter
301
+
302
+ if showRefs {
303
+ oldRefFilter := refFilter
304
+ fmt .Fprintf (os .Stderr , "References (included references marked with '+'):\n " )
305
+ refFilter = func (refname string ) bool {
306
+ b := oldRefFilter (refname )
307
+ if b {
308
+ fmt .Fprintf (os .Stderr , "+ %s\n " , refname )
309
+ } else {
310
+ fmt .Fprintf (os .Stderr , " %s\n " , refname )
311
+ }
312
+ return b
166
313
}
167
- if processTags {
168
- filters = append (filters , git .TagsFilter )
169
- }
170
- if processRemotes {
171
- filters = append (filters , git .RemotesFilter )
172
- }
173
- filter = git .OrFilter (filters ... )
174
- } else {
175
- filter = git .AllReferencesFilter
176
314
}
177
315
178
- historySize , err = sizes .ScanRepositoryUsingGraph (repo , filter , nameStyle , progress )
316
+ historySize , err = sizes .ScanRepositoryUsingGraph (repo , refFilter , nameStyle , progress )
179
317
if err != nil {
180
318
return fmt .Errorf ("error scanning repository: %s" , err )
181
319
}
0 commit comments