@@ -16,60 +16,200 @@ import (
1616 "github.com/spf13/pflag"
1717)
1818
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+
1963var ReleaseVersion string
2064var BuildVersion string
2165
2266type NegatedBoolValue struct {
2367 value * bool
2468}
2569
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
2973 return err
3074}
3175
32- func (b * NegatedBoolValue ) Get () interface {} {
33- return ! * b .value
76+ func (v * NegatedBoolValue ) Get () interface {} {
77+ return ! * v .value
3478}
3579
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 {
3882 return "true"
3983 } else {
40- return strconv .FormatBool (! * b .value )
84+ return strconv .FormatBool (! * v .value )
4185 }
4286}
4387
4488func (v * NegatedBoolValue ) Type () string {
4589 return "bool"
4690}
4791
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+
48155func main () {
49- err := mainImplementation ()
156+ err := mainImplementation (os . Args [ 1 :] )
50157 if err != nil {
51158 fmt .Fprintf (os .Stderr , "error: %s\n " , err )
52159 os .Exit (1 )
53160 }
54161}
55162
56- func mainImplementation () error {
57- var processBranches bool
58- var processTags bool
59- var processRemotes bool
163+ func mainImplementation (args []string ) error {
60164 var nameStyle sizes.NameStyle = sizes .NameStyleFull
61165 var cpuprofile string
62166 var jsonOutput bool
63167 var jsonVersion uint
64168 var threshold sizes.Threshold = 1
65169 var progress bool
66170 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+ )
67195
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"
69207
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"
73213
74214 flags .VarP (
75215 sizes .NewThresholdFlagValue (& threshold , 0 ),
@@ -105,6 +245,7 @@ func mainImplementation() error {
105245 atty = false
106246 }
107247 flags .BoolVar (& progress , "progress" , atty , "report progress to stderr" )
248+ flags .BoolVar (& showRefs , "show-refs" , false , "list the references being processed" )
108249 flags .BoolVar (& version , "version" , false , "report the git-sizer version number" )
109250 flags .Var (& NegatedBoolValue {& progress }, "no-progress" , "suppress progress output" )
110251 flags .Lookup ("no-progress" ).NoOptDefVal = "true"
@@ -114,7 +255,7 @@ func mainImplementation() error {
114255
115256 flags .SortFlags = false
116257
117- err = flags .Parse (os . Args [ 1 :] )
258+ err = flags .Parse (args )
118259 if err != nil {
119260 if err == pflag .ErrHelp {
120261 return nil
@@ -144,9 +285,7 @@ func mainImplementation() error {
144285 return nil
145286 }
146287
147- args := flags .Args ()
148-
149- if len (args ) != 0 {
288+ if len (flags .Args ()) != 0 {
150289 return errors .New ("excess arguments" )
151290 }
152291
@@ -158,24 +297,23 @@ func mainImplementation() error {
158297
159298 var historySize sizes.HistorySize
160299
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
166313 }
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
176314 }
177315
178- historySize , err = sizes .ScanRepositoryUsingGraph (repo , filter , nameStyle , progress )
316+ historySize , err = sizes .ScanRepositoryUsingGraph (repo , refFilter , nameStyle , progress )
179317 if err != nil {
180318 return fmt .Errorf ("error scanning repository: %s" , err )
181319 }
0 commit comments