Skip to content

Commit 583341e

Browse files
committed
function: implement uast_imports UDF
Closes #943 After changes to the structure of imports, the way we used to collect them is no longer valid, so now we're using the uast.AllImportPaths helper included in the bblfsh sdk to obtain import paths from nodes. Signed-off-by: Miguel Molina <[email protected]>
1 parent 1df9e0b commit 583341e

File tree

7 files changed

+148
-5
lines changed

7 files changed

+148
-5
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88

9+
### Added
10+
11+
- `uast_imports` function to gather import paths from an UAST.
12+
913
## [0.24.0-beta2] - 2019-07-31
1014

1115
### Changed

docs/using-gitbase/examples.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,27 @@ As result, you will get an array showing a list of the retrieved information. Ea
227227
+-------------------+-----------------------------------------------------------------------------------------------+
228228
```
229229

230+
## Extracting all import paths
231+
232+
```sql
233+
SELECT file_path,
234+
uast_imports(uast(blob_content, LANGUAGE(file_path, blob_content))) AS imports
235+
FROM refs
236+
NATURAL JOIN commit_files
237+
NATURAL JOIN blobs
238+
WHERE ref_name = 'HEAD' AND LANGUAGE(file_path) = 'Go';
239+
```
240+
241+
As result, you will get an array with an array of import paths for each node in the UAST.
242+
243+
```sh
244+
+-------------------------------------------------------------------------------------------------------------------+
245+
| file_path | imports |
246+
+-------------------+-----------------------------------------------------------------------------------------------+
247+
| _example/main.go | [["fmt","database/sql","github.com/sirupsen/logrus"]] |
248+
+-------------------+-----------------------------------------------------------------------------------------------+
249+
```
250+
230251
## Monitor the progress of a query
231252

232253
You can monitor the progress of a gitbase query (either a regular query or an index creation query using `SHOW PROCESSLIST`).

go.mod

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ go 1.12
44

55
require (
66
github.com/bblfsh/go-client/v4 v4.1.0
7-
github.com/bblfsh/sdk/v3 v3.1.0
7+
github.com/bblfsh/sdk/v3 v3.2.2
88
github.com/gliderlabs/ssh v0.2.0 // indirect
99
github.com/go-kit/kit v0.8.0
1010
github.com/go-sql-driver/mysql v1.4.1
@@ -14,7 +14,7 @@ require (
1414
github.com/miekg/dns v1.1.1 // indirect
1515
github.com/opentracing/opentracing-go v1.1.0
1616
github.com/prometheus/client_golang v1.0.0
17-
github.com/sirupsen/logrus v1.3.0
17+
github.com/sirupsen/logrus v1.4.2
1818
github.com/src-d/enry/v2 v2.0.0
1919
github.com/src-d/go-borges v0.0.0-20190628121335-da12a84d60fd
2020
github.com/src-d/go-git v4.7.0+incompatible
@@ -25,7 +25,6 @@ require (
2525
github.com/uber/jaeger-client-go v2.16.0+incompatible
2626
github.com/uber/jaeger-lib v2.0.0+incompatible // indirect
2727
go.uber.org/atomic v1.4.0 // indirect
28-
golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443 // indirect
2928
golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b // indirect
3029
golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect
3130
golang.org/x/sys v0.0.0-20190618155005-516e3c20635f // indirect

go.sum

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
2+
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
23
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
34
github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
45
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
@@ -33,9 +34,12 @@ github.com/bblfsh/go-client/v4 v4.1.0 h1:z9S5GrUSB0uiipbWauc5fV6D/R0LNBi65dhfP5u
3334
github.com/bblfsh/go-client/v4 v4.1.0/go.mod h1:UUAG7jrxSr7WHlFL/U8den1kLHfysZWJ9jA1Y0IiQ+0=
3435
github.com/bblfsh/sdk/v3 v3.1.0 h1:V+4DqGlqbxiAEAU0XlpTjjbq/g0ljfiFoh9jsIkfbtU=
3536
github.com/bblfsh/sdk/v3 v3.1.0/go.mod h1:juMiu8rP3lYJN1e4neEkSyzNieqiFceZzN4AOo0Rm1Q=
37+
github.com/bblfsh/sdk/v3 v3.2.2 h1:+Kr5hTK8ZklcjRQgfiMnM6JNI5faN1bsW/JZAHD8kyI=
38+
github.com/bblfsh/sdk/v3 v3.2.2/go.mod h1:LSY0KJDbK4tQHGIk3rEYX4sAeWgZzNqV1E3Bp30/Nrw=
3639
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
3740
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
3841
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
42+
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
3943
github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
4044
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
4145
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
@@ -219,6 +223,8 @@ github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjM
219223
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
220224
github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME=
221225
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
226+
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
227+
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
222228
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
223229
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
224230
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
@@ -230,6 +236,7 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
230236
github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
231237
github.com/src-d/enry/v2 v2.0.0 h1:2ADqfDHhroFwL1RGhMS9e15NkEwln8P4AABwVvIdAlo=
232238
github.com/src-d/enry/v2 v2.0.0/go.mod h1:qQeCMRwzMF3ckeGr+h0tJLdxXnq+NVZsIDMELj0t028=
239+
github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc=
233240
github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
234241
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
235242
github.com/src-d/go-borges v0.0.0-20190628121335-da12a84d60fd h1:jUbtZFWSqGX1DfD2evCwA4y7LIrWV0W8h06sjWZANf0=
@@ -278,8 +285,8 @@ golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnf
278285
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
279286
golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
280287
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
281-
golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443 h1:IcSOAf4PyMp3U3XbIEj1/xJ2BjNN2jWv7JoyOsMxXUU=
282-
golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
288+
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
289+
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
283290
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
284291
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
285292
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -289,6 +296,7 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
289296
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
290297
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
291298
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
299+
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
292300
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
293301
golang.org/x/net v0.0.0-20190227022144-312bce6e941f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
294302
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -299,6 +307,7 @@ golang.org/x/net v0.0.0-20190607181551-461777fb6f67/go.mod h1:z5CRVTTTmAJ677TzLL
299307
golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b h1:lkjdUzSyJ5P1+eal9fxXX9Xg2BTfswsonKUse48C0uE=
300308
golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
301309
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
310+
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
302311
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
303312
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
304313
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -364,6 +373,7 @@ gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzW
364373
gopkg.in/src-d/go-git.v4 v4.11.0/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYCkLokZk=
365374
gopkg.in/src-d/go-git.v4 v4.12.0 h1:CKgvBCJCcdfNnyXPYI4Cp8PaDDAmAPEN0CtfEdEAbd8=
366375
gopkg.in/src-d/go-git.v4 v4.12.0/go.mod h1:zjlNnzc1Wjn43v3Mtii7RVxiReNP0fIu9npcXKzuNp4=
376+
gopkg.in/src-d/go-log.v1 v1.0.2/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE=
367377
gopkg.in/src-d/go-siva.v1 v1.5.0 h1:WowvbZTlz0SPoV7WNCGktPSi2yRK78HPyXl7wYqDeHE=
368378
gopkg.in/src-d/go-siva.v1 v1.5.0/go.mod h1:tk1jnIXawd/PTlRNWdr5V5lC0PttNJmu1fv7wt7IZlw=
369379
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=

internal/function/registry.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ var Functions = []sql.Function{
1515
sql.Function2{Name: "uast_xpath", Fn: NewUASTXPath},
1616
sql.Function2{Name: "uast_extract", Fn: NewUASTExtract},
1717
sql.Function1{Name: "uast_children", Fn: NewUASTChildren},
18+
sql.Function1{Name: "uast_imports", Fn: NewUASTImports},
1819
sql.Function1{Name: "is_vendor", Fn: NewIsVendor},
1920
}

internal/function/uast.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,3 +759,70 @@ func getChildren(node nodes.Object) nodes.Array {
759759

760760
return children
761761
}
762+
763+
// UASTImports finds the imports in UAST nodes.
764+
type UASTImports struct {
765+
expression.UnaryExpression
766+
}
767+
768+
// NewUASTImports creates a new UASTImports node.
769+
func NewUASTImports(child sql.Expression) sql.Expression {
770+
return &UASTImports{expression.UnaryExpression{Child: child}}
771+
}
772+
773+
// Type implements the sql.Expression interface.
774+
func (f *UASTImports) Type() sql.Type {
775+
return sql.Array(sql.Array(sql.Text))
776+
}
777+
778+
// IsNullable implements the sql.Expression interface.
779+
func (f *UASTImports) IsNullable() bool { return true }
780+
781+
// Eval implements the sql.Expression interface.
782+
func (f *UASTImports) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
783+
span, ctx := ctx.Span("function.UASTImports")
784+
defer span.Finish()
785+
786+
child, err := f.Child.Eval(ctx, row)
787+
if err != nil {
788+
return nil, err
789+
}
790+
791+
nodes, err := getNodes(child)
792+
if err != nil {
793+
return nil, err
794+
}
795+
796+
if nodes == nil {
797+
return nil, nil
798+
}
799+
800+
var result = make([]interface{}, nodes.Size())
801+
for i := 0; i < nodes.Size(); i++ {
802+
node := nodes.ValueAt(i)
803+
imports := uast.AllImportPaths(node)
804+
nodeImports := make([]interface{}, len(imports))
805+
for j, imp := range imports {
806+
nodeImports[j] = imp
807+
}
808+
result[i] = nodeImports
809+
}
810+
811+
return result, nil
812+
}
813+
814+
func (f *UASTImports) String() string {
815+
return fmt.Sprintf("uast_imports(%s)", f.Child)
816+
}
817+
818+
// Children implements the sql.Expression interface.
819+
func (f *UASTImports) Children() []sql.Expression { return []sql.Expression{f.Child} }
820+
821+
// WithChildren implements the sql.Expression interface.
822+
func (f *UASTImports) WithChildren(children ...sql.Expression) (sql.Expression, error) {
823+
if len(children) != 1 {
824+
return nil, sql.ErrInvalidChildrenNumber.New(f, len(children), 1)
825+
}
826+
827+
return NewUASTImports(children[0]), nil
828+
}

internal/function/uast_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,47 @@ func TestExtractAnyProp(t *testing.T) {
360360
require.Nil(t, props)
361361
}
362362

363+
func TestUASTImports(t *testing.T) {
364+
code := `
365+
package foo
366+
367+
import "fmt"
368+
import "github.com/src-d/foo"
369+
import "gopkg.in/src-d/bar"
370+
371+
func main() {
372+
fmt.Println("Hello", foo.Foo, bar.Bar)
373+
}
374+
`
375+
376+
ctx, cleanup := setup(t)
377+
defer cleanup()
378+
379+
require := require.New(t)
380+
381+
f, err := NewUAST(
382+
expression.NewLiteral([]byte(code), sql.Blob),
383+
expression.NewLiteral("Go", sql.Text),
384+
)
385+
require.NoError(err)
386+
result, err := f.Eval(ctx, nil)
387+
require.NoError(err)
388+
require.NotNil(result)
389+
390+
result, err = NewUASTImports(expression.NewLiteral(result, sql.Blob)).Eval(ctx, nil)
391+
require.NoError(err)
392+
393+
expected := []interface{}{
394+
[]interface{}{
395+
"fmt",
396+
"github.com/src-d/foo",
397+
"gopkg.in/src-d/bar",
398+
},
399+
}
400+
401+
require.Equal(expected, result)
402+
}
403+
363404
func assertUASTBlobs(t *testing.T, ctx *sql.Context, a, b interface{}) {
364405
t.Helper()
365406
var require = require.New(t)

0 commit comments

Comments
 (0)