Skip to content

Commit f336716

Browse files
authored
Merge pull request #200 from boyter/issue196
Issue196
2 parents 143bc06 + 529b360 commit f336716

File tree

7 files changed

+220
-29
lines changed

7 files changed

+220
-29
lines changed

README.md

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,12 @@ cost of running some static analysis tools.
175175
### Usage
176176

177177
Command line usage of `scc` is designed to be as simple as possible.
178-
Full details can be found in `scc --help` or `scc -h`.
178+
Full details can be found in `scc --help` or `scc -h`. Note that the below reflects the state of master not a release.
179179

180180
```
181181
$ scc -h
182182
Sloc, Cloc and Code. Count lines of code in a directory with complexity estimation.
183-
Version 2.13.0
183+
Version 3.0.0 (beta)
184184
Ben Boyter <[email protected]> + Contributors
185185
186186
Usage:
@@ -195,7 +195,7 @@ Flags:
195195
--debug enable debug output
196196
--exclude-dir strings directories to exclude (default [.git,.hg,.svn])
197197
--file-gc-count int number of files to parse before turning the GC on (default 10000)
198-
-f, --format string set output format [tabular, wide, json, csv, cloc-yaml, html, html-table] (default "tabular")
198+
-f, --format string set output format [tabular, wide, json, csv, cloc-yaml, html, html-table, sql, sql-insert] (default "tabular")
199199
--format-multi string have multiple format output overriding --format [e.g. tabular:stdout,csv:file.csv,json:file.json]
200200
--gen identify generated files
201201
--generated-markers strings string markers in head of generated files (default [do not edit])
@@ -224,6 +224,7 @@ Flags:
224224
--remap-unknown string inspect files of unknown type and remap by checking for a string and remapping the language [e.g. "-*- C++ -*-":"C Header"]
225225
--size-unit string set size unit [si, binary, mixed, xkcd-kb, xkcd-kelly, xkcd-imaginary, xkcd-intel, xkcd-drive, xkcd-bakers] (default "si")
226226
-s, --sort string column to sort by [files, name, lines, blanks, code, comments, complexity] (default "files")
227+
--sql-project string use supplied name as the project identifier for the current run. Only valid with the --format sql or sql-insert option
227228
-t, --trace enable trace output (not recommended when processing multiple files)
228229
-v, --verbose verbose output
229230
--version version for scc
@@ -382,7 +383,7 @@ Note that in all cases if the remap rule does not apply normal #! rules will app
382383

383384
By default `scc` will output to the console. However you can produce output in other formats if you require.
384385

385-
The different options are `tabular, wide, json, csv, cloc-yaml, html, html-table`.
386+
The different options are `tabular, wide, json, csv, cloc-yaml, html, html-table, sql, sql-insert`.
386387

387388
Note that you can write `scc` output to disk using the `-o, --output` option. This allows you to specify a file to
388389
write your output to. For example `scc -f html -o output.html` will run `scc` against the current directory, and output
@@ -491,6 +492,39 @@ file and not just the summary.
491492
Note that this format if it has the `--by-file` option will give you the byte size of every file it `scc` reads allowing you to get a breakdown of the
492493
number of bytes processed.
493494

495+
#### SQL and SQL-Insert
496+
497+
The SQL output format "mostly" compatible with cloc's SQL output format https://github.com/AlDanial/cloc#sql-
498+
499+
While all queries on the cloc documentation should work as expected, you will not be able to append output from `scc` and `cloc` into the same database. This is because the table format is slightly different
500+
to account for scc including complexity counts and bytes.
501+
502+
The difference between `sql` and `sql-insert` is that `sql` will include table creation while the latter will only have the insert commands.
503+
504+
Usage is 100% the same as any other `scc` command but sql output will always contain per file details. You can compute totals yourself using SQL.
505+
506+
The below will run scc against the current directory, name the ouput as the project scc and then pipe the output to sqlite to put into the database code.db
507+
508+
```
509+
scc --format sql --sql-project scc . | sqlite3 code.db
510+
```
511+
512+
Assuming you then wanted to append another project
513+
514+
```
515+
scc --format sql-insert --sql-project redis . | sqlite3 code.db
516+
```
517+
518+
You could then run SQL against the database,
519+
520+
```
521+
sqlite3 code.db 'select project,file,max(nCode) as nL from t
522+
group by project order by nL desc;'
523+
```
524+
525+
See the cloc documentation for more examples.
526+
527+
494528
### Performance
495529

496530
Generally `scc` will the fastest code counter compared to any I am aware of and have compared against. The below comparisons are taken from the fastest alternative counters. See `Other similar projects` above to see all of the other code counters compared against. It is designed to scale to as many CPU's cores as you can provide.

SCC-OUTPUT-REPORT.html

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212
<tbody><tr>
1313
<th>Go</th>
1414
<th>34</th>
15-
<th>8088</th>
16-
<th>1323</th>
17-
<th>347</th>
18-
<th>6418</th>
19-
<th>1338</th>
20-
<th>321289</th>
15+
<th>8208</th>
16+
<th>1340</th>
17+
<th>349</th>
18+
<th>6519</th>
19+
<th>1352</th>
20+
<th>324777</th>
2121
</tr><tr>
2222
<th>Java</th>
2323
<th>24</th>
@@ -48,12 +48,12 @@
4848
</tr><tr>
4949
<th>Markdown</th>
5050
<th>8</th>
51-
<th>1133</th>
52-
<th>265</th>
51+
<th>1189</th>
52+
<th>283</th>
5353
<th>0</th>
54-
<th>868</th>
54+
<th>906</th>
5555
<th>0</th>
56-
<th>46552</th>
56+
<th>48490</th>
5757
</tr><tr>
5858
<th>CSS</th>
5959
<th>5</th>
@@ -93,12 +93,12 @@
9393
</tr><tr>
9494
<th>Shell</th>
9595
<th>3</th>
96-
<th>950</th>
97-
<th>132</th>
96+
<th>987</th>
97+
<th>136</th>
9898
<th>37</th>
99-
<th>781</th>
100-
<th>87</th>
101-
<th>33879</th>
99+
<th>814</th>
100+
<th>91</th>
101+
<th>35251</th>
102102
</tr><tr>
103103
<th>JavaServer Pages</th>
104104
<th>2</th>
@@ -553,11 +553,11 @@
553553
<tfoot><tr>
554554
<th>Total</th>
555555
<th>162</th>
556-
<th>24483</th>
557-
<th>2791</th>
558-
<th>1540</th>
559-
<th>20152</th>
560-
<th>2258</th>
561-
<th>1738364</th>
556+
<th>24696</th>
557+
<th>2830</th>
558+
<th>1542</th>
559+
<th>20324</th>
560+
<th>2276</th>
561+
<th>1745162</th>
562562
</tr></tfoot>
563563
</table></body></html>

main.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ func main() {
9393
"format",
9494
"f",
9595
"tabular",
96-
"set output format [tabular, wide, json, csv, cloc-yaml, html, html-table]",
96+
"set output format [tabular, wide, json, csv, cloc-yaml, html, html-table, sql, sql-insert]",
9797
)
9898
flags.StringSliceVarP(
9999
&processor.AllowListExtensions,
@@ -271,6 +271,12 @@ func main() {
271271
"",
272272
"have multiple format output overriding --format [e.g. tabular:stdout,csv:file.csv,json:file.json]",
273273
)
274+
flags.StringVar(
275+
&processor.SQLProject,
276+
"sql-project",
277+
"",
278+
"use supplied name as the project identifier for the current run. Only valid with the --format sql or sql-insert option",
279+
)
274280
flags.StringVar(
275281
&processor.RemapUnknown,
276282
"remap-unknown",

processor/formatters.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"io/ioutil"
99
"math"
1010
"os"
11+
"path/filepath"
1112
"sort"
1213
"strings"
1314
"time"
@@ -411,6 +412,66 @@ func toHtmlTable(input chan *FileJob) string {
411412
return str.String()
412413
}
413414

415+
func toSqlInsert(input chan *FileJob) string {
416+
var str strings.Builder
417+
projectName := SQLProject
418+
if projectName == "" {
419+
projectName = strings.Join(DirFilePaths, ",")
420+
}
421+
422+
str.WriteString("\nbegin transaction;")
423+
count := 0
424+
for res := range input {
425+
count++
426+
427+
dir, _ := filepath.Split(res.Location)
428+
429+
str.WriteString(fmt.Sprintf("\ninsert into t values('%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d, %d);",
430+
projectName, res.Language, res.Location, dir, res.Filename, res.Bytes, res.Blank, res.Comment, res.Code, res.Complexity))
431+
432+
// every 1000 files commit and start a new transaction to avoid overloading
433+
if count == 1000 {
434+
str.WriteString("\ncommit;")
435+
str.WriteString("\nbegin transaction;")
436+
count = 0
437+
}
438+
}
439+
if count != 1000 {
440+
str.WriteString("\ncommit;")
441+
}
442+
443+
currentTime := time.Now()
444+
es := float64(makeTimestampMilli()-startTimeMilli) * 0.001
445+
str.WriteString("\nbegin transaction;")
446+
str.WriteString(fmt.Sprintf("\ninsert into metadata values('%s', '%s', %f);", currentTime.Format("2006-01-02 15:04:05"), projectName, es))
447+
str.WriteString("\ncommit;")
448+
449+
return str.String()
450+
}
451+
452+
func toSql(input chan *FileJob) string {
453+
var str strings.Builder
454+
455+
str.WriteString(`create table metadata ( -- github.com/boyter/scc v ` + Version + `
456+
timestamp text,
457+
Project text,
458+
elapsed_s real);
459+
create table t (
460+
Project text ,
461+
Language text ,
462+
File text ,
463+
File_dirname text ,
464+
File_basename text ,
465+
nByte integer,
466+
nBlank integer,
467+
nComment integer,
468+
nCode integer,
469+
nComplexity integer );`)
470+
471+
str.WriteString(toSqlInsert(input))
472+
return str.String()
473+
}
474+
414475
func fileSummarize(input chan *FileJob) string {
415476
if FormatMulti != "" {
416477
return fileSummarizeMulti(input)
@@ -429,6 +490,10 @@ func fileSummarize(input chan *FileJob) string {
429490
return toHtml(input)
430491
case strings.ToLower(Format) == "html-table":
431492
return toHtmlTable(input)
493+
case strings.ToLower(Format) == "sql":
494+
return toSql(input)
495+
case strings.ToLower(Format) == "sql-insert":
496+
return toSqlInsert(input)
432497
}
433498

434499
return fileSummarizeShort(input)
@@ -476,6 +541,10 @@ func fileSummarizeMulti(input chan *FileJob) string {
476541
val = toHtml(i)
477542
case "html-table":
478543
val = toHtmlTable(i)
544+
case "sql":
545+
val = toSql(i)
546+
case "sql-insert":
547+
val = toSqlInsert(i)
479548
}
480549

481550
if t[1] == "stdout" {

processor/formatters_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,48 @@ func TestToCsvMultiple(t *testing.T) {
606606
}
607607
}
608608

609+
func TestToSQLSingle(t *testing.T) {
610+
inputChan := make(chan *FileJob, 1000)
611+
inputChan <- &FileJob{
612+
Language: "Go",
613+
Filename: "bbbb.go",
614+
Extension: "go",
615+
Location: "./",
616+
Bytes: 1000,
617+
Lines: 1000,
618+
Code: 1000,
619+
Comment: 1000,
620+
Blank: 1000,
621+
Complexity: 1000,
622+
WeightedComplexity: 1000,
623+
Binary: false,
624+
}
625+
close(inputChan)
626+
Debug = true // Increase coverage slightly
627+
res := toSql(inputChan)
628+
Debug = false
629+
630+
if !strings.Contains(res, `create table metadata`) {
631+
t.Error("Expected create table return", res)
632+
}
633+
634+
if !strings.Contains(res, `create table t`) {
635+
t.Error("Expected create table return", res)
636+
}
637+
638+
if !strings.Contains(res, `begin transaction`) {
639+
t.Error("Expected begin transaction return", res)
640+
}
641+
642+
if !strings.Contains(res, `insert into t values('', 'Go', './', './', 'bbbb.go', 1000, 1000, 1000, 1000, 1000);`) {
643+
t.Error("Expected insert return", res)
644+
}
645+
646+
if !strings.Contains(res, `insert into metadata values`) {
647+
t.Error("Expected insert return", res)
648+
}
649+
}
650+
609651
func TestFileSummarizeWide(t *testing.T) {
610652
inputChan := make(chan *FileJob, 1000)
611653
inputChan <- &FileJob{

processor/processor.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
)
1616

1717
// Version indicates the version of the application
18-
var Version = "2.13.0"
18+
var Version = "3.0.0 (beta)"
1919

2020
// Flags set via the CLI which control how the output is displayed
2121

@@ -103,6 +103,9 @@ var Format = ""
103103
// FormatMulti is a rule for defining multiple output formats
104104
var FormatMulti = ""
105105

106+
// SQLProject is used to store the name for the SQL insert formats but is optional
107+
var SQLProject = ""
108+
106109
// RemapUnknown allows remapping of unknown files with a string to search the content for
107110
var RemapUnknown = ""
108111

0 commit comments

Comments
 (0)