From d6a5af2c790bea1ddd7eb8565cfdf6e8781bcc26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1ximo=20Cuadros?= Date: Thu, 18 Apr 2019 01:17:23 +0200 Subject: [PATCH 1/3] function: LOC function implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Máximo Cuadros --- internal/function/loc.go | 156 ++++++++++++++++++++++++++++++++++ internal/function/loc_test.go | 56 ++++++++++++ internal/function/registry.go | 1 + 3 files changed, 213 insertions(+) create mode 100644 internal/function/loc.go create mode 100644 internal/function/loc_test.go diff --git a/internal/function/loc.go b/internal/function/loc.go new file mode 100644 index 000000000..829a34ff8 --- /dev/null +++ b/internal/function/loc.go @@ -0,0 +1,156 @@ +package function + +import ( + "bytes" + "errors" + "fmt" + + "github.com/hhatto/gocloc" + "gopkg.in/src-d/enry.v1" + "gopkg.in/src-d/go-mysql-server.v0/sql" +) + +var languages = gocloc.NewDefinedLanguages() + +var errEmptyInputValues = errors.New("empty input values") + +type LOC struct { + Left sql.Expression + Right sql.Expression +} + +// NewLOC creates a new LOC UDF. +func NewLOC(args ...sql.Expression) (sql.Expression, error) { + if len(args) != 2 { + return nil, sql.ErrInvalidArgumentNumber.New("2", len(args)) + } + + return &LOC{args[0], args[1]}, nil +} + +// Resolved implements the Expression interface. +func (f *LOC) Resolved() bool { + return f.Left.Resolved() && f.Right.Resolved() +} + +func (f *LOC) String() string { + return fmt.Sprintf("loc(%s, %s)", f.Left, f.Right) +} + +// IsNullable implements the Expression interface. +func (f *LOC) IsNullable() bool { + return f.Left.IsNullable() || f.Right.IsNullable() +} + +// Type implements the Expression interface. +func (LOC) Type() sql.Type { + return sql.JSON +} + +// TransformUp implements the Expression interface. +func (f *LOC) TransformUp(fn sql.TransformExprFunc) (sql.Expression, error) { + left, err := f.Left.TransformUp(fn) + if err != nil { + return nil, err + } + + right, err := f.Right.TransformUp(fn) + if err != nil { + return nil, err + } + + return fn(&LOC{left, right}) +} + +// Eval implements the Expression interface. +func (f *LOC) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { + span, ctx := ctx.Span("gitbase.LOC") + defer span.Finish() + path, blob, err := f.getInputValues(ctx, row) + if err != nil { + if err == errEmptyInputValues { + return nil, nil + } + + return nil, err + } + + lang := f.getLanguage(path, blob) + if lang == "" || languages.Langs[lang] == nil { + return nil, nil + } + + return gocloc.AnalyzeReader( + path, + languages.Langs[lang], + bytes.NewReader(blob), &gocloc.ClocOptions{}, + ), nil +} + +func (f *LOC) getInputValues(ctx *sql.Context, row sql.Row) (string, []byte, error) { + left, err := f.Left.Eval(ctx, row) + if err != nil { + return "", nil, err + } + + left, err = sql.Text.Convert(left) + if err != nil { + return "", nil, err + } + + right, err := f.Right.Eval(ctx, row) + if err != nil { + return "", nil, err + } + + right, err = sql.Blob.Convert(right) + if err != nil { + return "", nil, err + } + + if right == nil { + return "", nil, errEmptyInputValues + } + + path, ok := left.(string) + if !ok { + return "", nil, errEmptyInputValues + } + + blob, ok := right.([]byte) + + if !ok { + return "", nil, errEmptyInputValues + } + + if len(blob) == 0 || len(path) == 0 { + return "", nil, errEmptyInputValues + } + + return path, blob, nil +} + +func (f *LOC) getLanguage(path string, blob []byte) string { + hash := languageHash(path, blob) + + value, ok := languageCache.Get(hash) + if ok { + return value.(string) + } + + lang := enry.GetLanguage(path, blob) + if len(blob) > 0 { + languageCache.Add(hash, lang) + } + + return lang +} + +// Children implements the Expression interface. +func (f *LOC) Children() []sql.Expression { + if f.Right == nil { + return []sql.Expression{f.Left} + } + + return []sql.Expression{f.Left, f.Right} +} diff --git a/internal/function/loc_test.go b/internal/function/loc_test.go new file mode 100644 index 000000000..622b5cae5 --- /dev/null +++ b/internal/function/loc_test.go @@ -0,0 +1,56 @@ +package function + +import ( + "testing" + + "github.com/hhatto/gocloc" + "github.com/stretchr/testify/require" + "gopkg.in/src-d/go-errors.v1" + "gopkg.in/src-d/go-mysql-server.v0/sql" + "gopkg.in/src-d/go-mysql-server.v0/sql/expression" +) + +func TestLoc(t *testing.T) { + testCases := []struct { + name string + row sql.Row + expected interface{} + err *errors.Kind + }{ + {"left is null", sql.NewRow(nil), nil, nil}, + {"both are null", sql.NewRow(nil, nil), nil, nil}, + {"too few args given", sql.NewRow("foo.foobar"), nil, nil}, + {"too many args given", sql.NewRow("foo.rb", "bar", "baz"), nil, sql.ErrInvalidArgumentNumber}, + {"invalid blob type given", sql.NewRow("foo", 5), nil, sql.ErrInvalidType}, + {"path and blob are given", sql.NewRow("foo", "#!/usr/bin/env python\n\nprint 'foo'"), &gocloc.ClocFile{ + Code: 2, Comments: 0, Blanks: 1, Name: "foo", Lang: "", + }, nil}, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + require := require.New(t) + ctx := sql.NewEmptyContext() + + var args = make([]sql.Expression, len(tt.row)) + for i := range tt.row { + args[i] = expression.NewGetField(i, sql.Text, "", false) + } + + f, err := NewLOC(args...) + if err == nil { + var val interface{} + val, err = f.Eval(ctx, tt.row) + if tt.err == nil { + require.NoError(err) + require.Equal(tt.expected, val) + } + } + + if tt.err != nil { + require.Error(err) + require.True(tt.err.Is(err)) + } + }) + } +} diff --git a/internal/function/registry.go b/internal/function/registry.go index 53a8ab45f..fb4da7300 100644 --- a/internal/function/registry.go +++ b/internal/function/registry.go @@ -7,6 +7,7 @@ var Functions = []sql.Function{ sql.Function1{Name: "is_tag", Fn: NewIsTag}, sql.Function1{Name: "is_remote", Fn: NewIsRemote}, sql.FunctionN{Name: "language", Fn: NewLanguage}, + sql.FunctionN{Name: "loc", Fn: NewLOC}, sql.FunctionN{Name: "uast", Fn: NewUAST}, sql.Function3{Name: "uast_mode", Fn: NewUASTMode}, sql.Function2{Name: "uast_xpath", Fn: NewUASTXPath}, From 324c32e448a1f6dff69c253309cee692c0e79b6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1ximo=20Cuadros?= Date: Thu, 18 Apr 2019 01:17:44 +0200 Subject: [PATCH 2/3] vendor: add github.com/hhatto/gocloc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Máximo Cuadros --- Gopkg.lock | 9 + vendor/github.com/hhatto/gocloc/.gitignore | 10 + .../github.com/hhatto/gocloc/.goreleaser.yml | 34 ++ vendor/github.com/hhatto/gocloc/.travis.yml | 22 + vendor/github.com/hhatto/gocloc/Gopkg.toml | 11 + vendor/github.com/hhatto/gocloc/Makefile | 19 + vendor/github.com/hhatto/gocloc/README.md | 169 ++++++ vendor/github.com/hhatto/gocloc/bspool.go | 13 + .../hhatto/gocloc/examples/files.go | 28 + .../hhatto/gocloc/examples/languages.go | 28 + vendor/github.com/hhatto/gocloc/file.go | 173 ++++++ vendor/github.com/hhatto/gocloc/file_test.go | 203 +++++++ vendor/github.com/hhatto/gocloc/gocloc.go | 69 +++ vendor/github.com/hhatto/gocloc/json.go | 50 ++ vendor/github.com/hhatto/gocloc/language.go | 553 ++++++++++++++++++ .../github.com/hhatto/gocloc/language_test.go | 101 ++++ vendor/github.com/hhatto/gocloc/option.go | 21 + vendor/github.com/hhatto/gocloc/utils.go | 133 +++++ vendor/github.com/hhatto/gocloc/utils_test.go | 28 + vendor/github.com/hhatto/gocloc/xml.go | 75 +++ 20 files changed, 1749 insertions(+) create mode 100644 vendor/github.com/hhatto/gocloc/.gitignore create mode 100644 vendor/github.com/hhatto/gocloc/.goreleaser.yml create mode 100644 vendor/github.com/hhatto/gocloc/.travis.yml create mode 100644 vendor/github.com/hhatto/gocloc/Gopkg.toml create mode 100644 vendor/github.com/hhatto/gocloc/Makefile create mode 100644 vendor/github.com/hhatto/gocloc/README.md create mode 100644 vendor/github.com/hhatto/gocloc/bspool.go create mode 100644 vendor/github.com/hhatto/gocloc/examples/files.go create mode 100644 vendor/github.com/hhatto/gocloc/examples/languages.go create mode 100644 vendor/github.com/hhatto/gocloc/file.go create mode 100644 vendor/github.com/hhatto/gocloc/file_test.go create mode 100644 vendor/github.com/hhatto/gocloc/gocloc.go create mode 100644 vendor/github.com/hhatto/gocloc/json.go create mode 100644 vendor/github.com/hhatto/gocloc/language.go create mode 100644 vendor/github.com/hhatto/gocloc/language_test.go create mode 100644 vendor/github.com/hhatto/gocloc/option.go create mode 100644 vendor/github.com/hhatto/gocloc/utils.go create mode 100644 vendor/github.com/hhatto/gocloc/utils_test.go create mode 100644 vendor/github.com/hhatto/gocloc/xml.go diff --git a/Gopkg.lock b/Gopkg.lock index 0c665ff75..064108087 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -119,6 +119,14 @@ revision = "20f1fb78b0740ba8c3cb143a61e86ba5c8669768" version = "v0.5.0" +[[projects]] + digest = "1:2aeb7538d4b293b12da44c23a405f2652a05795361e871e2458b696e542f5768" + name = "github.com/hhatto/gocloc" + packages = ["."] + pruneopts = "" + revision = "250384e5268aee438f53d37f8641075d441b029c" + version = "v0.2.1" + [[projects]] branch = "master" digest = "1:95abc4eba158a39873bd4fabdee576d0ae13826b550f8b710881d80ae4093a0f" @@ -764,6 +772,7 @@ "github.com/BurntSushi/toml", "github.com/go-sql-driver/mysql", "github.com/hashicorp/golang-lru", + "github.com/hhatto/gocloc", "github.com/jessevdk/go-flags", "github.com/opentracing/opentracing-go", "github.com/sirupsen/logrus", diff --git a/vendor/github.com/hhatto/gocloc/.gitignore b/vendor/github.com/hhatto/gocloc/.gitignore new file mode 100644 index 000000000..e0734198b --- /dev/null +++ b/vendor/github.com/hhatto/gocloc/.gitignore @@ -0,0 +1,10 @@ +/bin +*.sw? +GTAGS +GPATH +GRTAGS + +Gopkg.lock +vendor/ +gocloc +dist/ diff --git a/vendor/github.com/hhatto/gocloc/.goreleaser.yml b/vendor/github.com/hhatto/gocloc/.goreleaser.yml new file mode 100644 index 000000000..392f394dd --- /dev/null +++ b/vendor/github.com/hhatto/gocloc/.goreleaser.yml @@ -0,0 +1,34 @@ +# This is an example goreleaser.yaml file with some sane defaults. +# Make sure to check the documentation at http://goreleaser.com +before: + hooks: + # you may remove this if you don't need go generate + - go generate ./... +builds: +- env: + - CGO_ENABLED=0 + main: './cmd/gocloc/main.go' + binary: gocloc + goos: + - windows + - darwin + - linux + goarch: + - amd64 +archive: + replacements: + darwin: Darwin + linux: Linux + windows: Windows + 386: i386 + amd64: x86_64 +checksum: + name_template: 'checksums.txt' +snapshot: + name_template: "{{ .Tag }}-next" +changelog: + sort: asc + filters: + exclude: + - '^docs:' + - '^test:' diff --git a/vendor/github.com/hhatto/gocloc/.travis.yml b/vendor/github.com/hhatto/gocloc/.travis.yml new file mode 100644 index 000000000..ac9dd82fe --- /dev/null +++ b/vendor/github.com/hhatto/gocloc/.travis.yml @@ -0,0 +1,22 @@ +language: go + +go: + - 1.x + - tip + +install: + - go get -u github.com/golang/dep/cmd/dep + - dep ensure + - go get -u golang.org/x/tools/cmd/goimports + - go get -v + +script: + - diff <(goimports -d *.go cmd/gocloc/main.go examples/*) <(printf "") + - go test -v ./ + +deploy: + - provider: script + skip_cleanup: true + script: curl -sL https://git.io/goreleaser | bash + on: + tags: true diff --git a/vendor/github.com/hhatto/gocloc/Gopkg.toml b/vendor/github.com/hhatto/gocloc/Gopkg.toml new file mode 100644 index 000000000..b423b815d --- /dev/null +++ b/vendor/github.com/hhatto/gocloc/Gopkg.toml @@ -0,0 +1,11 @@ +[[constraint]] + name = "github.com/jessevdk/go-flags" + version = "1.4.0" + +[[constraint]] + name = "gopkg.in/src-d/enry.v1" + version = "1.7.1" + +[prune] + go-tests = true + unused-packages = true diff --git a/vendor/github.com/hhatto/gocloc/Makefile b/vendor/github.com/hhatto/gocloc/Makefile new file mode 100644 index 000000000..0b372d043 --- /dev/null +++ b/vendor/github.com/hhatto/gocloc/Makefile @@ -0,0 +1,19 @@ +.PHONY: test build + +build: + go build + mkdir -p bin + go build -o ./bin/gocloc cmd/gocloc/main.go + +update-vendor: + dep ensure + +update-package: + go get -u github.com/hhatto/gocloc + +run-example: + go run examples/languages.go + go run examples/files.go + +test: + go test -v diff --git a/vendor/github.com/hhatto/gocloc/README.md b/vendor/github.com/hhatto/gocloc/README.md new file mode 100644 index 000000000..073b9412b --- /dev/null +++ b/vendor/github.com/hhatto/gocloc/README.md @@ -0,0 +1,169 @@ +# gocloc [![travis-ci](https://travis-ci.org/hhatto/gocloc.svg?branch=master)](https://travis-ci.org/hhatto/gocloc) [![Patreon](https://img.shields.io/badge/patreon-become%20a%20patron-red.svg)](https://www.patreon.com/hhatto) + +A little fast [cloc(Count Lines Of Code)](https://github.com/AlDanial/cloc), written in Go. +Inspired by [tokei](https://github.com/Aaronepower/tokei). + +## Installation + +``` +$ go get -u github.com/hhatto/gocloc/cmd/gocloc +``` + +## Usage + +### Basic Usage +``` +$ gocloc . +``` + +``` +$ gocloc . +------------------------------------------------------------------------------- +Language files blank comment code +------------------------------------------------------------------------------- +Markdown 3 8 0 18 +Go 1 29 1 323 +------------------------------------------------------------------------------- +TOTAL 4 37 1 341 +------------------------------------------------------------------------------- +``` + +### Integration Jenkins CI +use [SLOCCount Plugin](https://wiki.jenkins-ci.org/display/JENKINS/SLOCCount+Plugin). + +``` +$ cloc --by-file --output-type=sloccount . > sloccount.scc +``` + +``` +$ cat sloccount.scc +398 Go ./main.go +190 Go ./language.go +132 Markdown ./README.md +24 Go ./xml.go +18 Go ./file.go +15 Go ./option.go +``` + +## Support Languages +use `--show-lang` option + +``` +$ gocloc --show-lang +``` + +## Performance +* CPU 3.1GHz Intel Core i7 / 16GB 1600MHz DDR3 / MacOSX 10.11.3 +* cloc 1.66 +* tokei 1.5.1 +* gocloc [6a9d4f5](https://github.com/hhatto/gocloc/commit/6a9d4f5b3d4e5df28fe78a04e8741595e22ada50) +* target repository is [golang/go commit:633ab74](https://github.com/golang/go/tree/633ab7426a906b72dcf6f1d54e87f4ae926dc4e1) + +### cloc + +``` +$ time cloc . + 5171 text files. + 5052 unique files. + 420 files ignored. + +https://github.com/AlDanial/cloc v 1.66 T=23.31 s (204.0 files/s, 48203.3 lines/s) +----------------------------------------------------------------------------------- +Language files blank comment code +----------------------------------------------------------------------------------- +Go 4197 101140 125939 780280 +Assembly 331 6128 14654 40531 +HTML 41 4927 198 33316 +C 90 1076 940 7390 +Perl 12 185 177 1135 +Bourne Again Shell 25 209 266 933 +XML 4 85 9 623 +Bourne Shell 8 71 302 467 +Python 1 121 88 295 +DOS Batch 5 55 1 238 +JavaScript 4 48 122 231 +C/C++ Header 15 50 147 211 +CSS 3 51 9 176 +yacc 1 27 20 155 +Protocol Buffers 1 1 0 144 +Windows Resource File 4 25 0 116 +JSON 2 0 0 36 +make 7 12 10 35 +Fortran 90 2 1 3 8 +C++ 1 3 5 7 +awk 1 1 6 7 +----------------------------------------------------------------------------------- +SUM: 4755 114216 142896 866334 +----------------------------------------------------------------------------------- +cloc . 13.57s user 7.89s system 105% cpu 20.413 total +``` + +### tokei + +``` +$ time tokei --sort code . +------------------------------------------------------------------------------- + Language Files Total Blanks Comments Code +------------------------------------------------------------------------------- + Go 4272 1027537 103241 150411 773970 + Plain Text 28 0 0 0 137715 + Assembly 334 61318 6130 0 55188 + HTML 41 38441 4927 204 33316 + C 92 9436 1081 946 7409 + BASH 27 2134 260 570 1304 + XML 4 717 85 9 623 + Perl 10 1255 151 1096 343 + Python 1 504 121 56 327 + Batch 5 294 55 0 239 + JavaScript 4 401 48 122 231 + C Header 15 408 50 147 211 + CSS 3 236 51 9 176 + Protocol Buffers 1 145 1 0 144 + Markdown 3 0 0 0 115 + JSON 2 0 0 0 36 + Makefile 7 57 13 10 34 + FORTRAN Modern 2 12 1 3 8 + C++ 1 15 3 5 7 +------------------------------------------------------------------------------- + Total 4852 1142910 116218 153588 1011396 +------------------------------------------------------------------------------- +tokei --sort code . 1.27s user 0.06s system 99% cpu 1.328 total +``` + +### gocloc + +``` +$ time gocloc --exclude-ext=txt . +------------------------------------------------------------------------------- +Language files blank comment code +------------------------------------------------------------------------------- +Go 4197 101140 133703 773058 +Assembly 331 6128 14694 40510 +HTML 41 4927 198 33316 +C 90 1076 991 7389 +BASH 28 257 539 1330 +Perl 12 185 177 1135 +XML 4 85 9 623 +Python 1 121 88 295 +Batch 5 55 1 238 +JavaScript 4 48 122 231 +C Header 15 50 147 211 +CSS 3 51 9 176 +Yacc 1 27 20 155 +Protocol Buffers 1 1 0 144 +Markdown 3 29 0 86 +Plan9 Shell 4 25 42 74 +Bourne Shell 5 23 29 70 +JSON 2 0 0 36 +make 7 13 10 34 +FORTRAN Modern 2 1 3 8 +Awk 1 1 6 7 +C++ 1 3 5 7 +------------------------------------------------------------------------------- +TOTAL 4758 114246 150793 859133 +------------------------------------------------------------------------------- +gocloc --exclude-ext=txt . 0.76s user 0.15s system 116% cpu 0.775 total +``` + +## License +MIT diff --git a/vendor/github.com/hhatto/gocloc/bspool.go b/vendor/github.com/hhatto/gocloc/bspool.go new file mode 100644 index 000000000..dd1e2c007 --- /dev/null +++ b/vendor/github.com/hhatto/gocloc/bspool.go @@ -0,0 +1,13 @@ +package gocloc + +import "sync" + +var bsPool = sync.Pool{New: func() interface{} { return make([]byte, 0, 128*1024) }} + +func getByteSlice() []byte { + return bsPool.Get().([]byte) +} + +func putByteSlice(bs []byte) { + bsPool.Put(bs) +} diff --git a/vendor/github.com/hhatto/gocloc/examples/files.go b/vendor/github.com/hhatto/gocloc/examples/files.go new file mode 100644 index 000000000..6cc55bfcd --- /dev/null +++ b/vendor/github.com/hhatto/gocloc/examples/files.go @@ -0,0 +1,28 @@ +package main + +import ( + "fmt" + + "github.com/hhatto/gocloc" +) + +func main() { + languages := gocloc.NewDefinedLanguages() + options := gocloc.NewClocOptions() + paths := []string{ + ".", + } + + processor := gocloc.NewProcessor(languages, options) + result, err := processor.Analyze(paths) + if err != nil { + fmt.Printf("gocloc fail. error: %v\n", err) + return + } + + for _, item := range result.Files { + fmt.Println(item) + } + fmt.Println(result.Total) + fmt.Printf("%+v", result) +} diff --git a/vendor/github.com/hhatto/gocloc/examples/languages.go b/vendor/github.com/hhatto/gocloc/examples/languages.go new file mode 100644 index 000000000..90d36b909 --- /dev/null +++ b/vendor/github.com/hhatto/gocloc/examples/languages.go @@ -0,0 +1,28 @@ +package main + +import ( + "fmt" + + "github.com/hhatto/gocloc" +) + +func main() { + languages := gocloc.NewDefinedLanguages() + options := gocloc.NewClocOptions() + paths := []string{ + ".", + } + + processor := gocloc.NewProcessor(languages, options) + result, err := processor.Analyze(paths) + if err != nil { + fmt.Printf("gocloc fail. error: %v\n", err) + return + } + + for _, lang := range result.Languages { + fmt.Println(lang) + } + fmt.Println(result.Total) + fmt.Printf("%+v", result) +} diff --git a/vendor/github.com/hhatto/gocloc/file.go b/vendor/github.com/hhatto/gocloc/file.go new file mode 100644 index 000000000..590d2493d --- /dev/null +++ b/vendor/github.com/hhatto/gocloc/file.go @@ -0,0 +1,173 @@ +package gocloc + +import ( + "bufio" + "fmt" + "io" + "os" + "strings" +) + +type ClocFile struct { + Code int32 `xml:"code,attr" json:"code"` + Comments int32 `xml:"comment,attr" json:"comment"` + Blanks int32 `xml:"blank,attr" json:"blank"` + Name string `xml:"name,attr" json:"name"` + Lang string `xml:"language,attr" json"language"` +} + +type ClocFiles []ClocFile + +func (cf ClocFiles) Len() int { + return len(cf) +} +func (cf ClocFiles) Swap(i, j int) { + cf[i], cf[j] = cf[j], cf[i] +} +func (cf ClocFiles) Less(i, j int) bool { + if cf[i].Code == cf[j].Code { + return cf[i].Name < cf[j].Name + } + return cf[i].Code > cf[j].Code +} + +func AnalyzeFile(filename string, language *Language, opts *ClocOptions) *ClocFile { + fp, err := os.Open(filename) + if err != nil { + // ignore error + return &ClocFile{Name: filename} + } + defer fp.Close() + + return AnalyzeReader(filename, language, fp, opts) +} + +func AnalyzeReader(filename string, language *Language, file io.Reader, opts *ClocOptions) *ClocFile { + if opts.Debug { + fmt.Printf("filename=%v\n", filename) + } + + clocFile := &ClocFile{ + Name: filename, + } + + isFirstLine := true + isInComments := false + isInCommentsSame := false + buf := getByteSlice() + defer putByteSlice(buf) + scanner := bufio.NewScanner(file) + scanner.Buffer(buf, 1024*1024) + for scanner.Scan() { + lineOrg := scanner.Text() + line := strings.TrimSpace(lineOrg) + + if len(strings.TrimSpace(line)) == 0 { + clocFile.Blanks++ + if opts.Debug { + fmt.Printf("[BLNK,cd:%d,cm:%d,bk:%d,iscm:%v] %s\n", + clocFile.Code, clocFile.Comments, clocFile.Blanks, isInComments, lineOrg) + } + continue + } + + // shebang line is 'code' + if isFirstLine && strings.HasPrefix(line, "#!") { + clocFile.Code++ + isFirstLine = false + if opts.Debug { + fmt.Printf("[CODE,cd:%d,cm:%d,bk:%d,iscm:%v] %s\n", + clocFile.Code, clocFile.Comments, clocFile.Blanks, isInComments, lineOrg) + } + continue + } + + if len(language.lineComments) > 0 { + isSingleComment := false + if isFirstLine { + line = trimBOM(line) + } + for _, singleComment := range language.lineComments { + if strings.HasPrefix(line, singleComment) { + clocFile.Comments++ + isSingleComment = true + break + } + } + if isSingleComment { + if opts.Debug { + fmt.Printf("[COMM,cd:%d,cm:%d,bk:%d,iscm:%v] %s\n", + clocFile.Code, clocFile.Comments, clocFile.Blanks, isInComments, lineOrg) + } + continue + } + } + + isCode := false + multiLine := "" + multiLineEnd := "" + for i := range language.multiLines { + multiLine = language.multiLines[i][0] + multiLineEnd = language.multiLines[i][1] + if multiLine != "" { + if strings.HasPrefix(line, multiLine) { + isInComments = true + } else if strings.HasSuffix(line, multiLineEnd) { + isInComments = true + } else if containComments(line, multiLine, multiLineEnd) { + isInComments = true + if (multiLine != multiLineEnd) && + (strings.HasSuffix(line, multiLine) || strings.HasPrefix(line, multiLineEnd)) { + clocFile.Code++ + isCode = true + if opts.Debug { + fmt.Printf("[CODE,cd:%d,cm:%d,bk:%d,iscm:%v] %s\n", + clocFile.Code, clocFile.Comments, clocFile.Blanks, isInComments, lineOrg) + } + continue + } + } + if isInComments { + break + } + } + } + + if isInComments && isCode { + continue + } + + if isInComments { + if multiLine == multiLineEnd { + if strings.Count(line, multiLineEnd) == 2 { + isInComments = false + isInCommentsSame = false + } else if strings.HasPrefix(line, multiLineEnd) || + strings.HasSuffix(line, multiLineEnd) { + if isInCommentsSame { + isInComments = false + } + isInCommentsSame = !isInCommentsSame + } + } else { + if strings.Contains(line, multiLineEnd) { + isInComments = false + } + } + clocFile.Comments++ + if opts.Debug { + fmt.Printf("[COMM,cd:%d,cm:%d,bk:%d,iscm:%v,iscms:%v] %s\n", + clocFile.Code, clocFile.Comments, clocFile.Blanks, isInComments, isInCommentsSame, lineOrg) + } + continue + } + + clocFile.Code++ + if opts.Debug { + fmt.Printf("[CODE,cd:%d,cm:%d,bk:%d,iscm:%v] %s\n", + clocFile.Code, clocFile.Comments, clocFile.Blanks, isInComments, lineOrg) + } + } + + return clocFile +} diff --git a/vendor/github.com/hhatto/gocloc/file_test.go b/vendor/github.com/hhatto/gocloc/file_test.go new file mode 100644 index 000000000..fa19d3157 --- /dev/null +++ b/vendor/github.com/hhatto/gocloc/file_test.go @@ -0,0 +1,203 @@ +package gocloc + +import ( + "bytes" + "io/ioutil" + "os" + "testing" +) + +func TestAnalayzeFile4Python(t *testing.T) { + tmpfile, err := ioutil.TempFile("", "tmp.py") + if err != nil { + t.Logf("ioutil.TempFile() error. err=[%v]", err) + return + } + defer os.Remove(tmpfile.Name()) + + tmpfile.Write([]byte(`#!/bin/python + +class A: + """comment1 + comment2 + comment3 + """ + pass +`)) + + language := NewLanguage("Python", []string{"#"}, [][]string{{"\"\"\"", "\"\"\""}}) + clocOpts := NewClocOptions() + clocFile := AnalyzeFile(tmpfile.Name(), language, clocOpts) + tmpfile.Close() + + if clocFile.Blanks != 1 { + t.Errorf("invalid logic. blanks=%v", clocFile.Blanks) + } + if clocFile.Comments != 4 { + t.Errorf("invalid logic. comments=%v", clocFile.Comments) + } + if clocFile.Code != 3 { + t.Errorf("invalid logic. code=%v", clocFile.Code) + } +} + +func TestAnalayzeFile4PythonInvalid(t *testing.T) { + tmpfile, err := ioutil.TempFile("", "tmp.py") + if err != nil { + t.Logf("ioutil.TempFile() error. err=[%v]", err) + return + } + defer os.Remove(tmpfile.Name()) + + tmpfile.Write([]byte(`#!/bin/python + +class A: + """comment1 + comment2 + comment3""" + pass +`)) + + language := NewLanguage("Python", []string{"#"}, [][]string{{"\"\"\"", "\"\"\""}}) + clocOpts := NewClocOptions() + clocFile := AnalyzeFile(tmpfile.Name(), language, clocOpts) + tmpfile.Close() + + if clocFile.Blanks != 1 { + t.Errorf("invalid logic. blanks=%v", clocFile.Blanks) + } + if clocFile.Comments != 3 { + t.Errorf("invalid logic. comments=%v", clocFile.Comments) + } + if clocFile.Code != 3 { + t.Errorf("invalid logic. code=%v", clocFile.Code) + } +} + +func TestAnalayzeFile4Go(t *testing.T) { + tmpfile, err := ioutil.TempFile("", "tmp.go") + if err != nil { + t.Logf("ioutil.TempFile() error. err=[%v]", err) + return + } + defer os.Remove(tmpfile.Name()) + + tmpfile.Write([]byte(`package main + +func main() { + var n string /* + comment + comment + */ +} +`)) + + language := NewLanguage("Go", []string{"//"}, [][]string{{"/*", "*/"}}) + clocOpts := NewClocOptions() + clocFile := AnalyzeFile(tmpfile.Name(), language, clocOpts) + tmpfile.Close() + + if clocFile.Blanks != 1 { + t.Errorf("invalid logic. blanks=%v", clocFile.Blanks) + } + if clocFile.Comments != 3 { + t.Errorf("invalid logic. comments=%v", clocFile.Comments) + } + if clocFile.Code != 4 { + t.Errorf("invalid logic. code=%v", clocFile.Code) + } +} + +func TestAnalayzeFile4GoWithOnelineBlockComment(t *testing.T) { + t.SkipNow() + tmpfile, err := ioutil.TempFile("", "tmp.go") + if err != nil { + t.Logf("ioutil.TempFile() error. err=[%v]", err) + return + } + defer os.Remove(tmpfile.Name()) + + tmpfile.Write([]byte(`package main + +func main() { + st := "/*" + a := 1 + en := "*/" + /* comment */ +} +`)) + + language := NewLanguage("Go", []string{"//"}, [][]string{{"/*", "*/"}}) + clocOpts := NewClocOptions() + clocFile := AnalyzeFile(tmpfile.Name(), language, clocOpts) + tmpfile.Close() + + if clocFile.Blanks != 1 { + t.Errorf("invalid logic. blanks=%v", clocFile.Blanks) + } + if clocFile.Comments != 1 { // cloc->3, tokei->1, gocloc->4 + t.Errorf("invalid logic. comments=%v", clocFile.Comments) + } + if clocFile.Code != 6 { + t.Errorf("invalid logic. code=%v", clocFile.Code) + } +} + +func TestAnalayzeFile4GoWithCommentInnerBlockComment(t *testing.T) { + tmpfile, err := ioutil.TempFile("", "tmp.go") + if err != nil { + t.Logf("ioutil.TempFile() error. err=[%v]", err) + return + } + defer os.Remove(tmpfile.Name()) + + tmpfile.Write([]byte(`package main + +func main() { + // comment /* + a := 1 + b := 2 +} +`)) + + language := NewLanguage("Go", []string{"//"}, [][]string{{"/*", "*/"}}) + clocOpts := NewClocOptions() + clocFile := AnalyzeFile(tmpfile.Name(), language, clocOpts) + tmpfile.Close() + + if clocFile.Blanks != 1 { + t.Errorf("invalid logic. blanks=%v", clocFile.Blanks) + } + if clocFile.Comments != 1 { + t.Errorf("invalid logic. comments=%v", clocFile.Comments) + } + if clocFile.Code != 5 { + t.Errorf("invalid logic. code=%v", clocFile.Code) + } +} + +func TestAnalayzeReader(t *testing.T) { + buf := bytes.NewBuffer([]byte(`#!/bin/python + +class A: + """comment1 + comment2 + comment3 + """ + pass +`)) + + language := NewLanguage("Python", []string{"#"}, [][]string{{"\"\"\"", "\"\"\""}}) + clocOpts := NewClocOptions() + clocFile := AnalyzeReader("test.py", language, buf, clocOpts) + + if clocFile.Blanks != 1 { + t.Errorf("invalid logic. blanks=%v", clocFile.Blanks) + } + if clocFile.Comments != 4 { + t.Errorf("invalid logic. comments=%v", clocFile.Comments) + } + if clocFile.Code != 3 { + t.Errorf("invalid logic. code=%v", clocFile.Code) + } +} diff --git a/vendor/github.com/hhatto/gocloc/gocloc.go b/vendor/github.com/hhatto/gocloc/gocloc.go new file mode 100644 index 000000000..17237b689 --- /dev/null +++ b/vendor/github.com/hhatto/gocloc/gocloc.go @@ -0,0 +1,69 @@ +package gocloc + +type Processor struct { + langs *DefinedLanguages + opts *ClocOptions +} + +type Result struct { + Total *Language + Files map[string]*ClocFile + Languages map[string]*Language + MaxPathLength int +} + +func NewProcessor(langs *DefinedLanguages, options *ClocOptions) *Processor { + return &Processor{ + langs: langs, + opts: options, + } +} + +func (p *Processor) Analyze(paths []string) (*Result, error) { + total := NewLanguage("TOTAL", []string{}, [][]string{{"", ""}}) + languages, err := getAllFiles(paths, p.langs, p.opts) + if err != nil { + return nil, err + } + maxPathLen := 0 + num := 0 + for _, lang := range languages { + num += len(lang.Files) + for _, file := range lang.Files { + l := len(file) + if maxPathLen < l { + maxPathLen = l + } + } + } + clocFiles := make(map[string]*ClocFile, num) + + for _, language := range languages { + for _, file := range language.Files { + cf := AnalyzeFile(file, language, p.opts) + cf.Lang = language.Name + + language.Code += cf.Code + language.Comments += cf.Comments + language.Blanks += cf.Blanks + clocFiles[file] = cf + } + + files := int32(len(language.Files)) + if len(language.Files) <= 0 { + continue + } + + total.Total += files + total.Blanks += language.Blanks + total.Comments += language.Comments + total.Code += language.Code + } + + return &Result{ + Total: total, + Files: clocFiles, + Languages: languages, + MaxPathLength: maxPathLen, + }, nil +} diff --git a/vendor/github.com/hhatto/gocloc/json.go b/vendor/github.com/hhatto/gocloc/json.go new file mode 100644 index 000000000..247ee1b0b --- /dev/null +++ b/vendor/github.com/hhatto/gocloc/json.go @@ -0,0 +1,50 @@ +package gocloc + +type JSONLanguagesResult struct { + Languages []ClocLanguage `json:"languages"` + Total ClocLanguage `json:"total"` +} + +type JSONFilesResult struct { + Files []ClocFile `json:"files"` + Total ClocLanguage `json:"total"` +} + +func NewJSONLanguagesResultFromCloc(total *Language, sortedLanguages Languages) JSONLanguagesResult { + var langs []ClocLanguage + for _, language := range sortedLanguages { + c := ClocLanguage{ + Name: language.Name, + FilesCount: int32(len(language.Files)), + Code: language.Code, + Comments: language.Comments, + Blanks: language.Blanks, + } + langs = append(langs, c) + } + t := ClocLanguage{ + FilesCount: total.Total, + Code: total.Code, + Comments: total.Comments, + Blanks: total.Blanks, + } + + return JSONLanguagesResult{ + Languages: langs, + Total: t, + } +} + +func NewJSONFilesResultFromCloc(total *Language, sortedFiles ClocFiles) JSONFilesResult { + t := ClocLanguage{ + FilesCount: total.Total, + Code: total.Code, + Comments: total.Comments, + Blanks: total.Blanks, + } + + return JSONFilesResult{ + Files: sortedFiles, + Total: t, + } +} diff --git a/vendor/github.com/hhatto/gocloc/language.go b/vendor/github.com/hhatto/gocloc/language.go new file mode 100644 index 000000000..a5a3d0650 --- /dev/null +++ b/vendor/github.com/hhatto/gocloc/language.go @@ -0,0 +1,553 @@ +package gocloc + +import ( + "bufio" + "bytes" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "regexp" + "sort" + "strings" + "unicode" + + enry "gopkg.in/src-d/enry.v1" +) + +// ClocLanguage is provide for xml-cloc and json format +type ClocLanguage struct { + Name string `xml:"name,attr" json:"name,omitempty"` + FilesCount int32 `xml:"files_count,attr" json:"files"` + Code int32 `xml:"code,attr" json:"code"` + Comments int32 `xml:"comment,attr" json:"comment"` + Blanks int32 `xml:"blank,attr" json:"blank"` +} + +type Language struct { + Name string + lineComments []string + multiLines [][]string + Files []string + Code int32 + Comments int32 + Blanks int32 + Total int32 +} +type Languages []Language + +func (ls Languages) Len() int { + return len(ls) +} +func (ls Languages) Swap(i, j int) { + ls[i], ls[j] = ls[j], ls[i] +} +func (ls Languages) Less(i, j int) bool { + if ls[i].Code == ls[j].Code { + return ls[i].Name < ls[j].Name + } + return ls[i].Code > ls[j].Code +} + +var reShebangEnv = regexp.MustCompile("^#! *(\\S+/env) ([a-zA-Z]+)") +var reShebangLang = regexp.MustCompile("^#! *[.a-zA-Z/]+/([a-zA-Z]+)") + +var Exts = map[string]string{ + "as": "ActionScript", + "ada": "Ada", + "adb": "Ada", + "ads": "Ada", + "Ant": "Ant", + "adoc": "AsciiDoc", + "asciidoc": "AsciiDoc", + "asm": "Assembly", + "S": "Assembly", + "s": "Assembly", + "dats": "ATS", + "sats": "ATS", + "hats": "ATS", + "awk": "Awk", + "bat": "Batch", + "btm": "Batch", + "bb": "BitBake", + "cbl": "COBOL", + "cmd": "Batch", + "bash": "BASH", + "sh": "Bourne Shell", + "c": "C", + "carp": "Carp", + "csh": "C Shell", + "ec": "C", + "erl": "Erlang", + "hrl": "Erlang", + "pgc": "C", + "capnp": "Cap'n Proto", + "chpl": "Chapel", + "cs": "C#", + "clj": "Clojure", + "coffee": "CoffeeScript", + "cfm": "ColdFusion", + "cfc": "ColdFusion CFScript", + "cmake": "CMake", + "cc": "C++", + "cpp": "C++", + "cxx": "C++", + "pcc": "C++", + "c++": "C++", + "cr": "Crystal", + "css": "CSS", + "cu": "CUDA", + "d": "D", + "dart": "Dart", + "dtrace": "DTrace", + "dts": "Device Tree", + "dtsi": "Device Tree", + "e": "Eiffel", + "elm": "Elm", + "el": "LISP", + "exp": "Expect", + "ex": "Elixir", + "exs": "Elixir", + "feature": "Gherkin", + "fish": "Fish", + "fr": "Frege", + "fst": "F*", + "F#": "F#", // deplicated F#/GLSL + "GLSL": "GLSL", // both use ext '.fs' + "vs": "GLSL", + "shader": "HLSL", + "cg": "HLSL", + "cginc": "HLSL", + "hlsl": "HLSL", + "lean": "Lean", + "hlean": "Lean", + "lgt": "Logtalk", + "lisp": "LISP", + "lsp": "LISP", + "lua": "Lua", + "ls": "LiveScript", + "sc": "LISP", + "f": "FORTRAN Legacy", + "f77": "FORTRAN Legacy", + "for": "FORTRAN Legacy", + "ftn": "FORTRAN Legacy", + "pfo": "FORTRAN Legacy", + "f90": "FORTRAN Modern", + "f95": "FORTRAN Modern", + "f03": "FORTRAN Modern", + "f08": "FORTRAN Modern", + "go": "Go", + "groovy": "Groovy", + "gradle": "Groovy", + "h": "C Header", + "hs": "Haskell", + "hpp": "C++ Header", + "hh": "C++ Header", + "html": "HTML", + "hx": "Haxe", + "hxx": "C++ Header", + "idr": "Idris", + "il": "SKILL", + "ino": "Arduino Sketch", + "io": "Io", + "ipynb": "Jupyter Notebook", + "jai": "JAI", + "java": "Java", + "js": "JavaScript", + "jl": "Julia", + "json": "JSON", + "jsx": "JSX", + "kt": "Kotlin", + "lds": "LD Script", + "less": "LESS", + "Objective-C": "Objective-C", // deplicated Obj-C/Matlab/Mercury + "Matlab": "MATLAB", // both use ext '.m' + "Mercury": "Mercury", // use ext '.m' + "md": "Markdown", + "markdown": "Markdown", + "nix": "Nix", + "nsi": "NSIS", + "nsh": "NSIS", + "nu": "Nu", + "ML": "OCaml", + "ml": "OCaml", + "mli": "OCaml", + "mll": "OCaml", + "mly": "OCaml", + "mm": "Objective-C++", + "maven": "Maven", + "makefile": "Makefile", + "meson": "Meson", + "mustache": "Mustache", + "m4": "M4", + "l": "lex", + "nim": "Nim", + "php": "PHP", + "pas": "Pascal", + "PL": "Perl", + "pl": "Perl", + "pm": "Perl", + "plan9sh": "Plan9 Shell", + "pony": "Pony", + "ps1": "PowerShell", + "text": "Plain Text", + "txt": "Plain Text", + "polly": "Polly", + "proto": "Protocol Buffers", + "py": "Python", + "pxd": "Cython", + "pyx": "Cython", + "q": "Q", + "r": "R", + "R": "R", + "raml": "RAML", + "Rebol": "Rebol", + "red": "Red", + "Rmd": "RMarkdown", + "rake": "Ruby", + "rb": "Ruby", + "rkt": "Racket", + "rhtml": "Ruby HTML", + "rs": "Rust", + "rst": "ReStructuredText", + "sass": "Sass", + "scala": "Scala", + "scss": "Sass", + "scm": "Scheme", + "sed": "sed", + "stan": "Stan", + "sml": "Standard ML", + "sol": "Solidity", + "sql": "SQL", + "swift": "Swift", + "t": "Terra", + "tex": "TeX", + "thy": "Isabelle", + "tla": "TLA", + "sty": "TeX", + "tcl": "Tcl/Tk", + "toml": "TOML", + "ts": "TypeScript", + "mat": "Unity-Prefab", + "prefab": "Unity-Prefab", + "Coq": "Coq", + "vala": "Vala", + "Verilog": "Verilog", + "csproj": "MSBuild script", + "vcproj": "MSBuild script", + "vim": "VimL", + "vue": "Vue", + "xml": "XML", + "XML": "XML", + "xsd": "XSD", + "xsl": "XSLT", + "xslt": "XSLT", + "wxs": "WiX", + "yaml": "YAML", + "yml": "YAML", + "y": "Yacc", + "zep": "Zephir", + "zsh": "Zsh", +} + +var shebang2ext = map[string]string{ + "gosh": "scm", + "make": "make", + "perl": "pl", + "rc": "plan9sh", + "python": "py", + "ruby": "rb", + "escript": "erl", +} + +func getShebang(line string) (shebangLang string, ok bool) { + ret := reShebangEnv.FindAllStringSubmatch(line, -1) + if ret != nil && len(ret[0]) == 3 { + shebangLang = ret[0][2] + if sl, ok := shebang2ext[shebangLang]; ok { + return sl, ok + } + return shebangLang, true + } + + ret = reShebangLang.FindAllStringSubmatch(line, -1) + if ret != nil && len(ret[0]) >= 2 { + shebangLang = ret[0][1] + if sl, ok := shebang2ext[shebangLang]; ok { + return sl, ok + } + return shebangLang, true + } + + return "", false +} + +func getFileTypeByShebang(path string) (shebangLang string, ok bool) { + f, err := os.Open(path) + if err != nil { + return // ignore error + } + defer f.Close() + + reader := bufio.NewReader(f) + line, err := reader.ReadBytes('\n') + if err != nil { + return + } + line = bytes.TrimLeftFunc(line, unicode.IsSpace) + + if len(line) > 2 && line[0] == '#' && line[1] == '!' { + return getShebang(string(line)) + } + return +} + +func getFileType(path string, opts *ClocOptions) (ext string, ok bool) { + ext = filepath.Ext(path) + base := filepath.Base(path) + + switch ext { + case ".m", ".v", ".fs", ".r": + content, err := ioutil.ReadFile(path) + if err != nil { + return "", false + } + lang := enry.GetLanguage(path, content) + if opts.Debug { + fmt.Printf("path=%v, lang=%v\n", path, lang) + } + return lang, true + } + + switch base { + case "meson.build", "meson_options.txt": + return "meson", true + case "CMakeLists.txt": + return "cmake", true + case "configure.ac": + return "m4", true + case "Makefile.am": + return "makefile", true + case "build.xml": + return "Ant", true + case "pom.xml": + return "maven", true + } + + switch strings.ToLower(base) { + case "makefile": + return "makefile", true + case "nukefile": + return "nu", true + case "rebar": // skip + return "", false + } + + shebangLang, ok := getFileTypeByShebang(path) + if ok { + return shebangLang, true + } + + if len(ext) >= 2 { + return ext[1:], true + } + return ext, ok +} + +type MultiLine struct { + Start string + End string +} + +func NewLanguage(name string, lineComments []string, multiLines [][]string) *Language { + return &Language{ + Name: name, + lineComments: lineComments, + multiLines: multiLines, + Files: []string{}, + } +} + +func lang2exts(lang string) (exts string) { + es := []string{} + for ext, l := range Exts { + if lang == l { + switch lang { + case "Objective-C", "MATLAB", "Mercury": + ext = "m" + case "F#": + ext = "fs" + case "GLSL": + if ext == "GLSL" { + ext = "fs" + } + } + es = append(es, ext) + } + } + return strings.Join(es, ", ") +} + +type DefinedLanguages struct { + Langs map[string]*Language +} + +func (langs *DefinedLanguages) GetFormattedString() string { + var buf bytes.Buffer + printLangs := []string{} + for _, lang := range langs.Langs { + printLangs = append(printLangs, lang.Name) + } + sort.Strings(printLangs) + for _, lang := range printLangs { + buf.WriteString(fmt.Sprintf("%-30v (%s)\n", lang, lang2exts(lang))) + } + return buf.String() +} + +func NewDefinedLanguages() *DefinedLanguages { + return &DefinedLanguages{ + Langs: map[string]*Language{ + "ActionScript": NewLanguage("ActionScript", []string{"//"}, [][]string{{"/*", "*/"}}), + "Ada": NewLanguage("Ada", []string{"--"}, [][]string{{"", ""}}), + "Ant": NewLanguage("Ant", []string{""}}), + "AsciiDoc": NewLanguage("AsciiDoc", []string{}, [][]string{{"", ""}}), + "Assembly": NewLanguage("Assembly", []string{"//", ";", "#", "@", "|", "!"}, [][]string{{"/*", "*/"}}), + "ATS": NewLanguage("ATS", []string{"//"}, [][]string{{"/*", "*/"}, {"(*", "*)"}}), + "Awk": NewLanguage("Awk", []string{"#"}, [][]string{{"", ""}}), + "Arduino Sketch": NewLanguage("Arduino Sketch", []string{"//"}, [][]string{{"/*", "*/"}}), + "Batch": NewLanguage("Batch", []string{"REM", "rem"}, [][]string{{"", ""}}), + "BASH": NewLanguage("BASH", []string{"#"}, [][]string{{"", ""}}), + "BitBake": NewLanguage("BitBake", []string{"#"}, [][]string{{"", ""}}), + "C": NewLanguage("C", []string{"//"}, [][]string{{"/*", "*/"}}), + "C Header": NewLanguage("C Header", []string{"//"}, [][]string{{"/*", "*/"}}), + "C Shell": NewLanguage("C Shell", []string{"#"}, [][]string{{"", ""}}), + "Cap'n Proto": NewLanguage("Cap'n Proto", []string{"#"}, [][]string{{"", ""}}), + "Carp": NewLanguage("Carp", []string{";"}, [][]string{{"", ""}}), + "C#": NewLanguage("C#", []string{"//"}, [][]string{{"/*", "*/"}}), + "Chapel": NewLanguage("Chapel", []string{"//"}, [][]string{{"/*", "*/"}}), + "Clojure": NewLanguage("Clojure", []string{"#", "#_"}, [][]string{{"", ""}}), + "COBOL": NewLanguage("COBOL", []string{"*", "/"}, [][]string{{"", ""}}), + "CoffeeScript": NewLanguage("CoffeeScript", []string{"#"}, [][]string{{"###", "###"}}), + "Coq": NewLanguage("Coq", []string{"(*"}, [][]string{{"(*", "*)"}}), + "ColdFusion": NewLanguage("ColdFusion", []string{}, [][]string{{""}}), + "ColdFusion CFScript": NewLanguage("ColdFusion CFScript", []string{"//"}, [][]string{{"/*", "*/"}}), + "CMake": NewLanguage("CMake", []string{"#"}, [][]string{{"", ""}}), + "C++": NewLanguage("C++", []string{"//"}, [][]string{{"/*", "*/"}}), + "C++ Header": NewLanguage("C++ Header", []string{"//"}, [][]string{{"/*", "*/"}}), + "Crystal": NewLanguage("Crystal", []string{"#"}, [][]string{{"", ""}}), + "CSS": NewLanguage("CSS", []string{"//"}, [][]string{{"/*", "*/"}}), + "Cython": NewLanguage("Cython", []string{"#"}, [][]string{{"\"\"\"", "\"\"\""}}), + "CUDA": NewLanguage("CUDA", []string{"//"}, [][]string{{"/*", "*/"}}), + "D": NewLanguage("D", []string{"//"}, [][]string{{"/*", "*/"}}), + "Dart": NewLanguage("Dart", []string{"//"}, [][]string{{"/*", "*/"}}), + "DTrace": NewLanguage("DTrace", []string{}, [][]string{{"/*", "*/"}}), + "Device Tree": NewLanguage("Device Tree", []string{"//"}, [][]string{{"/*", "*/"}}), + "Eiffel": NewLanguage("Eiffel", []string{"--"}, [][]string{{"", ""}}), + "Elm": NewLanguage("Elm", []string{"--"}, [][]string{{"{-", "-}"}}), + "Elixir": NewLanguage("Elixir", []string{"#"}, [][]string{{"", ""}}), + "Erlang": NewLanguage("Erlang", []string{"%"}, [][]string{{"", ""}}), + "Expect": NewLanguage("Expect", []string{"#"}, [][]string{{"", ""}}), + "Fish": NewLanguage("Fish", []string{"#"}, [][]string{{"", ""}}), + "Frege": NewLanguage("Frege", []string{"--"}, [][]string{{"{-", "-}"}}), + "F*": NewLanguage("F*", []string{"(*", "//"}, [][]string{{"(*", "*)"}}), + "F#": NewLanguage("F#", []string{"(*"}, [][]string{{"(*", "*)"}}), + "Lean": NewLanguage("Lean", []string{"--"}, [][]string{{"/-", "-/"}}), + "Logtalk": NewLanguage("Logtalk", []string{"%"}, [][]string{{"", ""}}), + "Lua": NewLanguage("Lua", []string{"--"}, [][]string{{"--[[", "]]"}}), + "LISP": NewLanguage("LISP", []string{";;"}, [][]string{{"#|", "|#"}}), + "LiveScript": NewLanguage("LiveScript", []string{"#"}, [][]string{{"/*", "*/"}}), + "FORTRAN Legacy": NewLanguage("FORTRAN Legacy", []string{"c", "C", "!", "*"}, [][]string{{"", ""}}), + "FORTRAN Modern": NewLanguage("FORTRAN Modern", []string{"!"}, [][]string{{"", ""}}), + "Gherkin": NewLanguage("Gherkin", []string{"#"}, [][]string{{"", ""}}), + "GLSL": NewLanguage("GLSL", []string{"//"}, [][]string{{"/*", "*/"}}), + "Go": NewLanguage("Go", []string{"//"}, [][]string{{"/*", "*/"}}), + "Groovy": NewLanguage("Groovy", []string{"//"}, [][]string{{"/*", "*/"}}), + "Haskell": NewLanguage("Haskell", []string{"--"}, [][]string{{"{-", "-}"}}), + "Haxe": NewLanguage("Haxe", []string{"//"}, [][]string{{"/*", "*/"}}), + "HLSL": NewLanguage("HLSL", []string{"//"}, [][]string{{"/*", "*/"}}), + "HTML": NewLanguage("HTML", []string{"//", ""}}), + "Idris": NewLanguage("Idris", []string{"--"}, [][]string{{"{-", "-}"}}), + "Io": NewLanguage("Io", []string{"//", "#"}, [][]string{{"/*", "*/"}}), + "SKILL": NewLanguage("SKILL", []string{";"}, [][]string{{"/*", "*/"}}), + "JAI": NewLanguage("JAI", []string{"//"}, [][]string{{"/*", "*/"}}), + "Java": NewLanguage("Java", []string{"//"}, [][]string{{"/*", "*/"}}), + "JavaScript": NewLanguage("JavaScript", []string{"//"}, [][]string{{"/*", "*/"}}), + "Julia": NewLanguage("Julia", []string{"#"}, [][]string{{"#:=", ":=#"}}), + "Jupyter Notebook": NewLanguage("Jupyter Notebook", []string{"#"}, [][]string{{"", ""}}), + "JSON": NewLanguage("JSON", []string{}, [][]string{{"", ""}}), + "JSX": NewLanguage("JSX", []string{"//"}, [][]string{{"/*", "*/"}}), + "Kotlin": NewLanguage("Kotlin", []string{"//"}, [][]string{{"/*", "*/"}}), + "LD Script": NewLanguage("LD Script", []string{"//"}, [][]string{{"/*", "*/"}}), + "LESS": NewLanguage("LESS", []string{"//"}, [][]string{{"/*", "*/"}}), + "Objective-C": NewLanguage("Objective-C", []string{"//"}, [][]string{{"/*", "*/"}}), + "Markdown": NewLanguage("Markdown", []string{}, [][]string{{"", ""}}), + "Nix": NewLanguage("Nix", []string{"#"}, [][]string{{"/*", "*/"}}), + "NSIS": NewLanguage("NSIS", []string{"#", ";"}, [][]string{{"/*", "*/"}}), + "Nu": NewLanguage("Nu", []string{";", "#"}, [][]string{{"", ""}}), + "OCaml": NewLanguage("OCaml", []string{}, [][]string{{"(*", "*)"}}), + "Objective-C++": NewLanguage("Objective-C++", []string{"//"}, [][]string{{"/*", "*/"}}), + "Makefile": NewLanguage("Makefile", []string{"#"}, [][]string{{"", ""}}), + "MATLAB": NewLanguage("MATLAB", []string{"%"}, [][]string{{"%{", "}%"}}), + "Mercury": NewLanguage("Mercury", []string{"%"}, [][]string{{"/*", "*/"}}), + "Maven": NewLanguage("Maven", []string{""}}), + "Meson": NewLanguage("Meson", []string{"#"}, [][]string{{"", ""}}), + "Mustache": NewLanguage("Mustache", []string{}, [][]string{{"{{!", "}}"}}), + "M4": NewLanguage("M4", []string{"#"}, [][]string{{"", ""}}), + "Nim": NewLanguage("Nim", []string{"#"}, [][]string{{"#[", "]#"}}), + "lex": NewLanguage("lex", []string{}, [][]string{{"/*", "*/"}}), + "PHP": NewLanguage("PHP", []string{"#", "//"}, [][]string{{"/*", "*/"}}), + "Pascal": NewLanguage("Pascal", []string{"//"}, [][]string{{"{", ")"}}), + "Perl": NewLanguage("Perl", []string{"#"}, [][]string{{":=", ":=cut"}}), + "Plain Text": NewLanguage("Plain Text", []string{}, [][]string{{"", ""}}), + "Plan9 Shell": NewLanguage("Plan9 Shell", []string{"#"}, [][]string{{"", ""}}), + "Pony": NewLanguage("Pony", []string{"//"}, [][]string{{"/*", "*/"}}), + "PowerShell": NewLanguage("PowerShell", []string{"#"}, [][]string{{"<#", "#>"}}), + "Polly": NewLanguage("Polly", []string{""}}), + "Protocol Buffers": NewLanguage("Protocol Buffers", []string{"//"}, [][]string{{"", ""}}), + "Python": NewLanguage("Python", []string{"#"}, [][]string{{"\"\"\"", "\"\"\""}}), + "Q": NewLanguage("Q", []string{"/ "}, [][]string{{"\\", "/"}, {"/", "\\"}}), + "R": NewLanguage("R", []string{"#"}, [][]string{{"", ""}}), + "Rebol": NewLanguage("Rebol", []string{";"}, [][]string{{"", ""}}), + "Red": NewLanguage("Red", []string{";"}, [][]string{{"", ""}}), + "RMarkdown": NewLanguage("RMarkdown", []string{}, [][]string{{"", ""}}), + "RAML": NewLanguage("RAML", []string{"#"}, [][]string{{"", ""}}), + "Racket": NewLanguage("Racket", []string{";"}, [][]string{{"#|", "|#"}}), + "ReStructuredText": NewLanguage("ReStructuredText", []string{}, [][]string{{"", ""}}), + "Ruby": NewLanguage("Ruby", []string{"#"}, [][]string{{":=begin", ":=end"}}), + "Ruby HTML": NewLanguage("Ruby HTML", []string{""}}), + "Rust": NewLanguage("Rust", []string{"//", "///", "//!"}, [][]string{{"/*", "*/"}}), + "Scala": NewLanguage("Scala", []string{"//"}, [][]string{{"/*", "*/"}}), + "Sass": NewLanguage("Sass", []string{"//"}, [][]string{{"/*", "*/"}}), + "Scheme": NewLanguage("Scheme", []string{";"}, [][]string{{"#|", "|#"}}), + "sed": NewLanguage("sed", []string{"#"}, [][]string{{"", ""}}), + "Stan": NewLanguage("Stan", []string{"//"}, [][]string{{"/*", "*/"}}), + "Solidity": NewLanguage("Solidity", []string{"//"}, [][]string{{"/*", "*/"}}), + "Bourne Shell": NewLanguage("Bourne Shell", []string{"#"}, [][]string{{"", ""}}), + "Standard ML": NewLanguage("Standard ML", []string{}, [][]string{{"(*", "*)"}}), + "SQL": NewLanguage("SQL", []string{"--"}, [][]string{{"/*", "*/"}}), + "Swift": NewLanguage("Swift", []string{"//"}, [][]string{{"/*", "*/"}}), + "Terra": NewLanguage("Terra", []string{"--"}, [][]string{{"--[[", "]]"}}), + "TeX": NewLanguage("TeX", []string{"%"}, [][]string{{"", ""}}), + "Isabelle": NewLanguage("Isabelle", []string{}, [][]string{{"(*", "*)"}}), + "TLA": NewLanguage("TLA", []string{"/*"}, [][]string{{"(*", "*)"}}), + "Tcl/Tk": NewLanguage("Tcl/Tk", []string{"#"}, [][]string{{"", ""}}), + "TOML": NewLanguage("TOML", []string{"#"}, [][]string{{"", ""}}), + "TypeScript": NewLanguage("TypeScript", []string{"//"}, [][]string{{"/*", "*/"}}), + "Unity-Prefab": NewLanguage("Unity-Prefab", []string{}, [][]string{{"", ""}}), + "MSBuild script": NewLanguage("MSBuild script", []string{""}}), + "Vala": NewLanguage("Vala", []string{"//"}, [][]string{{"/*", "*/"}}), + "Verilog": NewLanguage("Verilog", []string{"//"}, [][]string{{"/*", "*/"}}), + "VimL": NewLanguage("VimL", []string{`"`}, [][]string{{"", ""}}), + "Vue": NewLanguage("Vue", []string{""}}), + "WiX": NewLanguage("WiX", []string{""}}), + "XML": NewLanguage("XML", []string{""}}), + "XSLT": NewLanguage("XSLT", []string{""}}), + "XSD": NewLanguage("XSD", []string{""}}), + "YAML": NewLanguage("YAML", []string{"#"}, [][]string{{"", ""}}), + "Yacc": NewLanguage("Yacc", []string{"//"}, [][]string{{"/*", "*/"}}), + "Zephir": NewLanguage("Zephir", []string{"//"}, [][]string{{"/*", "*/"}}), + "Zsh": NewLanguage("Zsh", []string{"#"}, [][]string{{"", ""}}), + }, + } +} diff --git a/vendor/github.com/hhatto/gocloc/language_test.go b/vendor/github.com/hhatto/gocloc/language_test.go new file mode 100644 index 000000000..e4b9d7274 --- /dev/null +++ b/vendor/github.com/hhatto/gocloc/language_test.go @@ -0,0 +1,101 @@ +package gocloc + +import "testing" + +func TestGetShebang(t *testing.T) { + lang := "py" + shebang := "#!/usr/bin/env python" + + s, ok := getShebang(shebang) + if !ok { + t.Errorf("invalid logic. shebang=[%v]", shebang) + } + + if lang != s { + t.Errorf("invalid logic. lang=[%v] shebang=[%v]", lang, s) + } +} + +func TestGetShebangWithSpace(t *testing.T) { + lang := "py" + shebang := "#! /usr/bin/env python" + + s, ok := getShebang(shebang) + if !ok { + t.Errorf("invalid logic. shebang=[%v]", shebang) + } + + if lang != s { + t.Errorf("invalid logic. lang=[%v] shebang=[%v]", lang, s) + } +} + +func TestGetShebangBashWithEnv(t *testing.T) { + lang := "bash" + shebang := "#!/usr/bin/env bash" + + s, ok := getShebang(shebang) + if !ok { + t.Errorf("invalid logic. shebang=[%v]", shebang) + } + + if lang != s { + t.Errorf("invalid logic. lang=[%v] shebang=[%v]", lang, s) + } +} + +func TestGetShebangBash(t *testing.T) { + lang := "bash" + shebang := "#!/usr/bin/bash" + + s, ok := getShebang(shebang) + if !ok { + t.Errorf("invalid logic. shebang=[%v]", shebang) + } + + if lang != s { + t.Errorf("invalid logic. lang=[%v] shebang=[%v]", lang, s) + } +} + +func TestGetShebangBashWithSpace(t *testing.T) { + lang := "bash" + shebang := "#! /usr/bin/bash" + + s, ok := getShebang(shebang) + if !ok { + t.Errorf("invalid logic. shebang=[%v]", shebang) + } + + if lang != s { + t.Errorf("invalid logic. lang=[%v] shebang=[%v]", lang, s) + } +} + +func TestGetShebangPlan9Shell(t *testing.T) { + lang := "plan9sh" + shebang := "#!/usr/rc" + + s, ok := getShebang(shebang) + if !ok { + t.Errorf("invalid logic. shebang=[%v]", shebang) + } + + if lang != s { + t.Errorf("invalid logic. lang=[%v] shebang=[%v]", lang, s) + } +} + +func TestGetShebangStartDot(t *testing.T) { + lang := "pl" + shebang := "#!./perl -o" + + s, ok := getShebang(shebang) + if !ok { + t.Errorf("invalid logic. shebang=[%v]", shebang) + } + + if lang != s { + t.Errorf("invalid logic. lang=[%v] shebang=[%v]", lang, s) + } +} diff --git a/vendor/github.com/hhatto/gocloc/option.go b/vendor/github.com/hhatto/gocloc/option.go new file mode 100644 index 000000000..29a4c0fe8 --- /dev/null +++ b/vendor/github.com/hhatto/gocloc/option.go @@ -0,0 +1,21 @@ +package gocloc + +import "regexp" + +type ClocOptions struct { + Debug bool + SkipDuplicated bool + ExcludeExts map[string]struct{} + IncludeLangs map[string]struct{} + ReNotMatchDir *regexp.Regexp + ReMatchDir *regexp.Regexp +} + +func NewClocOptions() *ClocOptions { + return &ClocOptions{ + Debug: false, + SkipDuplicated: false, + ExcludeExts: make(map[string]struct{}), + IncludeLangs: make(map[string]struct{}), + } +} diff --git a/vendor/github.com/hhatto/gocloc/utils.go b/vendor/github.com/hhatto/gocloc/utils.go new file mode 100644 index 000000000..dd2d4cf41 --- /dev/null +++ b/vendor/github.com/hhatto/gocloc/utils.go @@ -0,0 +1,133 @@ +package gocloc + +import ( + "crypto/md5" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" +) + +func trimBOM(line string) string { + l := len(line) + if l >= 3 { + if line[0] == 0xef && line[1] == 0xbb && line[2] == 0xbf { + trimLine := line[3:] + return trimLine + } + } + return line +} + +func containComments(line, commentStart, commentEnd string) bool { + inComments := 0 + for i := 0; i < len(line)-(len(commentStart)-1); i++ { + section := line[i : i+len(commentStart)] + + if section == commentStart { + inComments++ + } else if section == commentEnd { + if inComments != 0 { + inComments-- + } + } + } + return inComments != 0 +} + +func checkMD5Sum(path string, fileCache map[string]struct{}) (ignore bool) { + content, err := ioutil.ReadFile(path) + if err != nil { + return true + } + + // calc md5sum + hash := md5.Sum(content) + c := fmt.Sprintf("%x", hash) + if _, ok := fileCache[c]; ok { + return true + } + + fileCache[c] = struct{}{} + return false +} + +func isVCSDir(path string) bool { + if len(path) > 1 && path[0] == os.PathSeparator { + path = path[1:] + } + vcsDirs := []string{".bzr", ".cvs", ".hg", ".git", ".svn"} + for _, dir := range vcsDirs { + if strings.Contains(path, dir) { + return true + } + } + return false +} + +// getAllFiles return all of the files to be analyzed in paths. +func getAllFiles(paths []string, languages *DefinedLanguages, opts *ClocOptions) (result map[string]*Language, err error) { + result = make(map[string]*Language, 0) + fileCache := make(map[string]struct{}) + + for _, root := range paths { + vcsInRoot := isVCSDir(root) + err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + if !vcsInRoot && isVCSDir(path) { + return nil + } + + // check not-match directory + dir := filepath.Dir(path) + if opts.ReNotMatchDir != nil && opts.ReNotMatchDir.MatchString(dir) { + return nil + } + + if opts.ReMatchDir != nil && !opts.ReMatchDir.MatchString(dir) { + return nil + } + + if ext, ok := getFileType(path, opts); ok { + if targetExt, ok := Exts[ext]; ok { + // check exclude extension + if _, ok := opts.ExcludeExts[targetExt]; ok { + return nil + } + + if len(opts.IncludeLangs) != 0 { + if _, ok = opts.IncludeLangs[targetExt]; !ok { + return nil + } + } + + if !opts.SkipDuplicated { + ignore := checkMD5Sum(path, fileCache) + if ignore { + if opts.Debug { + fmt.Printf("[ignore=%v] find same md5\n", path) + } + return nil + } + } + + if _, ok := result[targetExt]; !ok { + result[targetExt] = NewLanguage( + languages.Langs[targetExt].Name, + languages.Langs[targetExt].lineComments, + languages.Langs[targetExt].multiLines) + } + result[targetExt].Files = append(result[targetExt].Files, path) + } + } + return nil + }) + } + return +} diff --git a/vendor/github.com/hhatto/gocloc/utils_test.go b/vendor/github.com/hhatto/gocloc/utils_test.go new file mode 100644 index 000000000..cdebebb04 --- /dev/null +++ b/vendor/github.com/hhatto/gocloc/utils_test.go @@ -0,0 +1,28 @@ +package gocloc + +import "testing" + +func TestContainComments(t *testing.T) { + line := "/* hoge */" + st := "/*" + ed := "*/" + if containComments(line, st, ed) { + t.Errorf("invalid") + } + + line = "/* comment" + if !containComments(line, st, ed) { + t.Errorf("invalid") + } +} + +func TestCheckMD5SumIgnore(t *testing.T) { + fileCache := make(map[string]struct{}) + + if checkMD5Sum("./utils_test.go", fileCache) { + t.Errorf("invalid sequence") + } + if !checkMD5Sum("./utils_test.go", fileCache) { + t.Errorf("invalid sequence") + } +} diff --git a/vendor/github.com/hhatto/gocloc/xml.go b/vendor/github.com/hhatto/gocloc/xml.go new file mode 100644 index 000000000..dba3fdff8 --- /dev/null +++ b/vendor/github.com/hhatto/gocloc/xml.go @@ -0,0 +1,75 @@ +package gocloc + +import ( + "encoding/xml" + "fmt" +) + +type XMLResultType int8 + +const ( + XMLResultWithLangs XMLResultType = iota + XMLResultWithFiles +) + +type XMLTotalLanguages struct { + SumFiles int32 `xml:"sum_files,attr"` + Code int32 `xml:"code,attr"` + Comment int32 `xml:"comment,attr"` + Blank int32 `xml:"blank,attr"` +} +type XMLResultLanguages struct { + Languages []ClocLanguage `xml:"language"` + Total XMLTotalLanguages `xml:"total"` +} + +type XMLTotalFiles struct { + Code int32 `xml:"code,attr"` + Comment int32 `xml:"comment,attr"` + Blank int32 `xml:"blank,attr"` +} +type XMLResultFiles struct { + Files []ClocFile `xml:"file"` + Total XMLTotalFiles `xml:"total"` +} + +type XMLResult struct { + XMLName xml.Name `xml:"results"` + XMLFiles *XMLResultFiles `xml:"files,omitempty"` + XMLLanguages *XMLResultLanguages `xml:"languages,omitempty"` +} + +func (x *XMLResult) Encode() { + if output, err := xml.MarshalIndent(x, "", " "); err == nil { + fmt.Printf(xml.Header) + fmt.Println(string(output)) + } +} + +func NewXMLResultFromCloc(total *Language, sortedLanguages Languages, option XMLResultType) *XMLResult { + var langs []ClocLanguage + for _, language := range sortedLanguages { + c := ClocLanguage{ + Name: language.Name, + FilesCount: int32(len(language.Files)), + Code: language.Code, + Comments: language.Comments, + Blanks: language.Blanks, + } + langs = append(langs, c) + } + t := XMLTotalLanguages{ + Code: total.Code, + Comment: total.Comments, + Blank: total.Blanks, + SumFiles: total.Total, + } + f := &XMLResultLanguages{ + Languages: langs, + Total: t, + } + + return &XMLResult{ + XMLLanguages: f, + } +} From a9f8b81d5295d6a7451c377dabb4503be2f9532d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1ximo=20Cuadros?= Date: Fri, 19 Apr 2019 13:50:07 +0200 Subject: [PATCH 3/3] doc: add loc function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Máximo Cuadros --- docs/using-gitbase/examples.md | 20 ++++++++++++++++++-- docs/using-gitbase/functions.md | 2 +- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/docs/using-gitbase/examples.md b/docs/using-gitbase/examples.md index b2e54fc57..e57e85092 100644 --- a/docs/using-gitbase/examples.md +++ b/docs/using-gitbase/examples.md @@ -42,7 +42,7 @@ FROM WHERE num > 1; ``` -## Get the number of blobs per HEAD commit +## Get the number of blobs per HEAD commit ```sql SELECT COUNT(commit_hash), @@ -76,6 +76,22 @@ GROUP BY committer_email, repo_id; ``` +## Report of line count per file from HEAD references + +```sql +SELECT + LANGUAGE(file_path, blob_content) as lang, + SUM(JSON_EXTRACT(LOC(file_path, blob_content), '$.Code')) as code, + SUM(JSON_EXTRACT(LOC(file_path, blob_content), '$.Comments')) as comments, + SUM(JSON_EXTRACT(LOC(file_path, blob_content), '$.Blanks')) as blanks, + COUNT(1) as files +FROM commit_files +NATURAL JOIN refs +NATURAL JOIN blobs +WHERE ref_name='HEAD' +GROUP BY lang; +``` + ## Files from first 6 commits from HEAD references that contains some key and are not in vendor directory ```sql @@ -201,4 +217,4 @@ To kill a query that's currently running you can use the value in `Id`. If we we ```sql KILL QUERY 168; -``` \ No newline at end of file +``` diff --git a/docs/using-gitbase/functions.md b/docs/using-gitbase/functions.md index 47b196e96..f2ca661d8 100644 --- a/docs/using-gitbase/functions.md +++ b/docs/using-gitbase/functions.md @@ -14,7 +14,7 @@ To make some common tasks easier for the user, there are some functions to inter |`uast_xpath(blob, xpath) blob`| performs an XPath query over the given UAST nodes | |`uast_extract(blob, key) text array`| extracts information identified by the given key from the uast nodes | |`uast_children(blob) blob`| returns a flattened array of the children UAST nodes from each one of the UAST nodes in the given array | - +|`loc(path, blob) json`| returns a JSON map, containing the lines of code of a file, separated in three categories: Code, Blank and Comment lines | ## Standard functions These are all functions that are available because they are implemented in `go-mysql-server`, used by gitbase.