@@ -17,7 +17,7 @@ import (
17
17
18
18
"github.com/mattn/go-runewidth"
19
19
20
- "golang.org/x/text/language"
20
+ glanguage "golang.org/x/text/language"
21
21
gmessage "golang.org/x/text/message"
22
22
"gopkg.in/yaml.v2"
23
23
)
@@ -42,6 +42,29 @@ var tabularWideFormatBody = "%-33s %9d %9d %8d %9d %8d %10d %16.2f\n"
42
42
var tabularWideFormatFile = "%s %9d %8d %9d %8d %10d %16.2f\n "
43
43
var wideFormatFileTruncate = 42
44
44
45
+ var openMetricsMetadata = `# TYPE scc_files count
46
+ # HELP scc_files Number of sourcecode files.
47
+ # TYPE scc_lines count
48
+ # UNIT scc_lines lines
49
+ # HELP scc_lines Number of lines.
50
+ # TYPE scc_code count
51
+ # UNIT scc_code lines
52
+ # HELP scc_code Number of lines of actual code.
53
+ # TYPE scc_comments count
54
+ # HELP scc_comments Number of comments.
55
+ # TYPE scc_blanks count
56
+ # UNIT scc_blanks lines
57
+ # HELP scc_blanks Number of blank lines.
58
+ # TYPE scc_complexity count
59
+ # UNIT scc_complexity lines
60
+ # HELP scc_complexity Code complexity.
61
+ # TYPE scc_bytes count
62
+ # UNIT scc_bytes bytes
63
+ # HELP scc_bytes Size in bytes.
64
+ `
65
+ var openMetricsSummaryRecordFormat = "scc_%s{language=\" %s\" } %d\n "
66
+ var openMetricsFileRecordFormat = "scc_%s{language=\" %s\" , file=\" %s\" } %d\n "
67
+
45
68
func sortSummaryFiles (summary * LanguageSummary ) {
46
69
switch {
47
70
case SortBy == "name" || SortBy == "names" || SortBy == "language" || SortBy == "languages" :
@@ -200,54 +223,7 @@ func toClocYAML(input chan *FileJob) string {
200
223
201
224
func toJSON (input chan * FileJob ) string {
202
225
startTime := makeTimestampMilli ()
203
- languages := map [string ]LanguageSummary {}
204
-
205
- for res := range input {
206
- _ , ok := languages [res .Language ]
207
-
208
- if ! ok {
209
- files := []* FileJob {}
210
- if Files {
211
- files = append (files , res )
212
- }
213
-
214
- languages [res .Language ] = LanguageSummary {
215
- Name : res .Language ,
216
- Lines : res .Lines ,
217
- Code : res .Code ,
218
- Comment : res .Comment ,
219
- Blank : res .Blank ,
220
- Complexity : res .Complexity ,
221
- Count : 1 ,
222
- Files : files ,
223
- Bytes : res .Bytes ,
224
- }
225
- } else {
226
- tmp := languages [res .Language ]
227
- files := tmp .Files
228
- if Files {
229
- files = append (files , res )
230
- }
231
-
232
- languages [res .Language ] = LanguageSummary {
233
- Name : res .Language ,
234
- Lines : tmp .Lines + res .Lines ,
235
- Code : tmp .Code + res .Code ,
236
- Comment : tmp .Comment + res .Comment ,
237
- Blank : tmp .Blank + res .Blank ,
238
- Complexity : tmp .Complexity + res .Complexity ,
239
- Count : tmp .Count + 1 ,
240
- Files : files ,
241
- Bytes : res .Bytes + tmp .Bytes ,
242
- }
243
- }
244
- }
245
-
246
- language := []LanguageSummary {}
247
- for _ , summary := range languages {
248
- language = append (language , summary )
249
- }
250
-
226
+ language := aggregateLanguageSummary (input )
251
227
language = sortLanguageSummary (language )
252
228
253
229
jsonString , _ := json .Marshal (language )
@@ -268,53 +244,7 @@ func toCSV(input chan *FileJob) string {
268
244
}
269
245
270
246
func toCSVSummary (input chan * FileJob ) string {
271
- languages := map [string ]LanguageSummary {}
272
-
273
- for res := range input {
274
- _ , ok := languages [res .Language ]
275
-
276
- if ! ok {
277
- files := []* FileJob {}
278
- if Files {
279
- files = append (files , res )
280
- }
281
-
282
- languages [res .Language ] = LanguageSummary {
283
- Name : res .Language ,
284
- Lines : res .Lines ,
285
- Code : res .Code ,
286
- Comment : res .Comment ,
287
- Blank : res .Blank ,
288
- Complexity : res .Complexity ,
289
- Count : 1 ,
290
- Files : files ,
291
- Bytes : res .Bytes ,
292
- }
293
- } else {
294
- tmp := languages [res .Language ]
295
- files := tmp .Files
296
- if Files {
297
- files = append (files , res )
298
- }
299
-
300
- languages [res .Language ] = LanguageSummary {
301
- Name : res .Language ,
302
- Lines : tmp .Lines + res .Lines ,
303
- Code : tmp .Code + res .Code ,
304
- Comment : tmp .Comment + res .Comment ,
305
- Blank : tmp .Blank + res .Blank ,
306
- Complexity : tmp .Complexity + res .Complexity ,
307
- Count : tmp .Count + 1 ,
308
- Files : files ,
309
- Bytes : res .Bytes + tmp .Bytes ,
310
- }
311
- }
312
- }
313
-
314
- language := []LanguageSummary {}
315
- for _ , summary := range languages {
316
- language = append (language , summary )
317
- }
247
+ language := aggregateLanguageSummary (input )
318
248
language = sortLanguageSummary (language )
319
249
320
250
records := [][]string {{
@@ -380,6 +310,47 @@ func toCSVFiles(input chan *FileJob) string {
380
310
return b .String ()
381
311
}
382
312
313
+ func toOpenMetrics (input chan * FileJob ) string {
314
+ if Files {
315
+ return toOpenMetricsFiles (input )
316
+ }
317
+
318
+ return toOpenMetricsSummary (input )
319
+ }
320
+
321
+ func toOpenMetricsSummary (input chan * FileJob ) string {
322
+ language := aggregateLanguageSummary (input )
323
+ language = sortLanguageSummary (language )
324
+
325
+ var sb strings.Builder
326
+ sb .WriteString (openMetricsMetadata )
327
+ for _ , result := range language {
328
+ sb .WriteString (fmt .Sprintf (openMetricsSummaryRecordFormat , "files" , result .Name , result .Count ))
329
+ sb .WriteString (fmt .Sprintf (openMetricsSummaryRecordFormat , "lines" , result .Name , result .Lines ))
330
+ sb .WriteString (fmt .Sprintf (openMetricsSummaryRecordFormat , "code" , result .Name , result .Code ))
331
+ sb .WriteString (fmt .Sprintf (openMetricsSummaryRecordFormat , "comments" , result .Name , result .Comment ))
332
+ sb .WriteString (fmt .Sprintf (openMetricsSummaryRecordFormat , "blanks" , result .Name , result .Blank ))
333
+ sb .WriteString (fmt .Sprintf (openMetricsSummaryRecordFormat , "complexity" , result .Name , result .Complexity ))
334
+ sb .WriteString (fmt .Sprintf (openMetricsSummaryRecordFormat , "bytes" , result .Name , result .Bytes ))
335
+ }
336
+ return sb .String ()
337
+ }
338
+
339
+ func toOpenMetricsFiles (input chan * FileJob ) string {
340
+ var sb strings.Builder
341
+ sb .WriteString (openMetricsMetadata )
342
+ for file := range input {
343
+ var filename = strings .ReplaceAll (file .Location , "\\ " , "\\ \\ " )
344
+ sb .WriteString (fmt .Sprintf (openMetricsFileRecordFormat , "lines" , file .Language , filename , file .Lines ))
345
+ sb .WriteString (fmt .Sprintf (openMetricsFileRecordFormat , "code" , file .Language , filename , file .Code ))
346
+ sb .WriteString (fmt .Sprintf (openMetricsFileRecordFormat , "comments" , file .Language , filename , file .Comment ))
347
+ sb .WriteString (fmt .Sprintf (openMetricsFileRecordFormat , "blanks" , file .Language , filename , file .Blank ))
348
+ sb .WriteString (fmt .Sprintf (openMetricsFileRecordFormat , "complexity" , file .Language , filename , file .Complexity ))
349
+ sb .WriteString (fmt .Sprintf (openMetricsFileRecordFormat , "bytes" , file .Language , filename , file .Bytes ))
350
+ }
351
+ return sb .String ()
352
+ }
353
+
383
354
// For very large repositories CSV stream can be used which prints results out as they come in
384
355
// with the express idea of lowering memory usage, see https://github.com/boyter/scc/issues/210 for
385
356
// the background on why this might be needed
@@ -610,6 +581,8 @@ func fileSummarize(input chan *FileJob) string {
610
581
return toSql (input )
611
582
case strings .ToLower (Format ) == "sql-insert" :
612
583
return toSqlInsert (input )
584
+ case strings .ToLower (Format ) == "openmetrics" :
585
+ return toOpenMetrics (input )
613
586
}
614
587
615
588
return fileSummarizeShort (input )
@@ -665,6 +638,8 @@ func fileSummarizeMulti(input chan *FileJob) string {
665
638
val = toSql (i )
666
639
case "sql-insert" :
667
640
val = toSqlInsert (i )
641
+ case "openmetrics" :
642
+ val = toOpenMetrics (i )
668
643
}
669
644
670
645
if t [1 ] == "stdout" {
@@ -1000,7 +975,7 @@ func calculateCocomoSLOCCount(sumCode int64, str *strings.Builder) {
1000
975
estimatedPeopleRequired := estimatedEffort / estimatedScheduleMonths
1001
976
estimatedCost := EstimateCost (estimatedEffort , AverageWage , Overhead )
1002
977
1003
- p := gmessage .NewPrinter (language .Make (os .Getenv ("LANG" )))
978
+ p := gmessage .NewPrinter (glanguage .Make (os .Getenv ("LANG" )))
1004
979
1005
980
str .WriteString (p .Sprintf ("Total Physical Source Lines of Code (SLOC) = %d\n " , sumCode ))
1006
981
str .WriteString (p .Sprintf ("Development Effort Estimate, Person-Years (Person-Months) = %.2f (%.2f)\n " , estimatedEffort / 12 , estimatedEffort ))
@@ -1018,7 +993,7 @@ func calculateCocomo(sumCode int64, str *strings.Builder) {
1018
993
estimatedScheduleMonths := EstimateScheduleMonths (estimatedEffort )
1019
994
estimatedPeopleRequired := estimatedEffort / estimatedScheduleMonths
1020
995
1021
- p := gmessage .NewPrinter (language .Make (os .Getenv ("LANG" )))
996
+ p := gmessage .NewPrinter (glanguage .Make (os .Getenv ("LANG" )))
1022
997
1023
998
str .WriteString (p .Sprintf ("Estimated Cost to Develop (%s) %s%d\n " , CocomoProjectType , CurrencySymbol , int64 (estimatedCost )))
1024
999
str .WriteString (p .Sprintf ("Estimated Schedule Effort (%s) %.2f months\n " , CocomoProjectType , estimatedScheduleMonths ))
@@ -1093,6 +1068,58 @@ func isLeapYear(year int) bool {
1093
1068
return leapFlag
1094
1069
}
1095
1070
1071
+ func aggregateLanguageSummary (input chan * FileJob ) []LanguageSummary {
1072
+ languages := map [string ]LanguageSummary {}
1073
+
1074
+ for res := range input {
1075
+ _ , ok := languages [res .Language ]
1076
+
1077
+ if ! ok {
1078
+ var files []* FileJob
1079
+ if Files {
1080
+ files = append (files , res )
1081
+ }
1082
+
1083
+ languages [res .Language ] = LanguageSummary {
1084
+ Name : res .Language ,
1085
+ Lines : res .Lines ,
1086
+ Code : res .Code ,
1087
+ Comment : res .Comment ,
1088
+ Blank : res .Blank ,
1089
+ Complexity : res .Complexity ,
1090
+ Count : 1 ,
1091
+ Files : files ,
1092
+ Bytes : res .Bytes ,
1093
+ }
1094
+ } else {
1095
+ tmp := languages [res .Language ]
1096
+ files := tmp .Files
1097
+ if Files {
1098
+ files = append (files , res )
1099
+ }
1100
+
1101
+ languages [res .Language ] = LanguageSummary {
1102
+ Name : res .Language ,
1103
+ Lines : tmp .Lines + res .Lines ,
1104
+ Code : tmp .Code + res .Code ,
1105
+ Comment : tmp .Comment + res .Comment ,
1106
+ Blank : tmp .Blank + res .Blank ,
1107
+ Complexity : tmp .Complexity + res .Complexity ,
1108
+ Count : tmp .Count + 1 ,
1109
+ Files : files ,
1110
+ Bytes : res .Bytes + tmp .Bytes ,
1111
+ }
1112
+ }
1113
+ }
1114
+
1115
+ var language []LanguageSummary
1116
+ for _ , summary := range languages {
1117
+ language = append (language , summary )
1118
+ }
1119
+
1120
+ return language
1121
+ }
1122
+
1096
1123
func sortLanguageSummary (language []LanguageSummary ) []LanguageSummary {
1097
1124
// Cater for the common case of adding plural even for those options that don't make sense
1098
1125
// as its quite common for those who English is not a first language to make a simple mistake
0 commit comments