Skip to content

Commit

Permalink
initial golang callgraph implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
emilwareus committed Mar 1, 2024
1 parent 58ac790 commit c66044f
Show file tree
Hide file tree
Showing 26 changed files with 896 additions and 45 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,4 @@ test/resolve/testdata/gradle/*/**
**.gradle-init-script.debricked.groovy
test/resolve/testdata/gradle/gradle.debricked.lock
/mvnproj/target
debricked-call-graph-golang
14 changes: 8 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,15 @@ require (
github.com/stretchr/objx v0.5.0 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
golang.org/x/crypto v0.16.0 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/term v0.15.0 // indirect
github.com/yuin/goldmark v1.7.0 // indirect
golang.org/x/crypto v0.19.0 // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/telemetry v0.0.0-20240222153655-3df865e588ac // indirect
golang.org/x/term v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.13.0 // indirect
golang.org/x/tools v0.18.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
17 changes: 17 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.7.0 h1:EfOIvIMZIzHdB/R/zVrikYLPPwJlfMcNczJFMs1m6sA=
github.com/yuin/goldmark v1.7.0/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
Expand All @@ -280,6 +282,8 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
Expand Down Expand Up @@ -317,6 +321,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down Expand Up @@ -355,6 +361,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
Expand All @@ -377,6 +385,7 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down Expand Up @@ -426,13 +435,19 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240222153655-3df865e588ac h1:ki77bVtFouxWgn3Q21wz6tOBcbD4Yhn21/KrwRrHeM4=
golang.org/x/telemetry v0.0.0-20240222153655-3df865e588ac/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down Expand Up @@ -500,6 +515,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
25 changes: 19 additions & 6 deletions internal/callgraph/cgexec/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,19 @@ type ICommand interface {
GetArgs() []string
GetDir() string
Signal(process *os.Process, signal os.Signal) error
GetStdOut() *bytes.Buffer
GetStdErr() *bytes.Buffer
}

type Command struct {
osCmd *exec.Cmd
osCmd *exec.Cmd
stdoutBuf *bytes.Buffer
stderrBuf *bytes.Buffer
}

func NewCommand(osCmd *exec.Cmd) *Command {
return &Command{osCmd}
var stdoutBuf, stderrBuf bytes.Buffer
return &Command{osCmd, &stdoutBuf, &stderrBuf}

Check failure on line 34 in internal/callgraph/cgexec/command.go

View workflow job for this annotation

GitHub Actions / Lint

return with no blank line before (nlreturn)
}

func (cmd Command) SetStderr(stderr *bytes.Buffer) {
Expand Down Expand Up @@ -65,9 +70,17 @@ func (cmd Command) Signal(process *os.Process, signal os.Signal) error {
return process.Signal(signal)
}

func (cmd Command) GetStdOut() *bytes.Buffer {
return cmd.stdoutBuf
}

func (cmd Command) GetStdErr() *bytes.Buffer {
return cmd.stderrBuf
}

func RunCommand(cmd ICommand, ctx IContext) error {
args := strings.Join(cmd.GetArgs(), " ")
var stdoutBuf, stderrBuf bytes.Buffer

var err error
var outputCmd []byte
if ctx == nil {
Expand All @@ -79,8 +92,8 @@ func RunCommand(cmd ICommand, ctx IContext) error {
return err
}

cmd.SetStderr(&stderrBuf)
cmd.SetStdout(&stdoutBuf)
cmd.SetStderr(cmd.GetStdErr())
cmd.SetStdout(cmd.GetStdOut())

// Start the external process
if err := cmd.Start(); err != nil {
Expand All @@ -95,7 +108,7 @@ func RunCommand(cmd ICommand, ctx IContext) error {
go func() {
err := cmd.Wait()
if err != nil {
err = fmt.Errorf("Command '%s' executed in folder '%s' gave the following error: \n%s\n%s", args, cmd.GetDir(), stdoutBuf.String(), stderrBuf.String())
err = fmt.Errorf("Command '%s' executed in folder '%s' gave the following error: \n%s\n%s", args, cmd.GetDir(), cmd.GetStdOut().String(), cmd.GetStdErr().String())
}

done <- err
Expand Down
8 changes: 8 additions & 0 deletions internal/callgraph/cgexec/testdata/command_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,11 @@ func (m CommandMock) GetDir() string {
func (m CommandMock) Signal(process *os.Process, signal os.Signal) error {
return m.SignalError
}

func (m CommandMock) GetStdOut() *bytes.Buffer {
return &bytes.Buffer{}
}

func (m CommandMock) GetStdErr() *bytes.Buffer {
return &bytes.Buffer{}
}
4 changes: 2 additions & 2 deletions internal/callgraph/finder/finder.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package finder

type IFinder interface {
FindMavenRoots(files []string) ([]string, error)
FindJavaClassDirs(files []string, findJars bool) ([]string, error)
FindRoots(files []string) ([]string, error)
FindDependencyDirs(files []string, findJars bool) ([]string, error)
FindFiles(paths []string, exclusions []string) ([]string, error)
}
60 changes: 60 additions & 0 deletions internal/callgraph/finder/golangfinder/finder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package golanfinder

import (
"os"
"path/filepath"

"github.com/debricked/cli/internal/callgraph/finder"
"github.com/debricked/cli/internal/file"
)

type GolangFinder struct{}

func (f GolangFinder) FindRoots(files []string) ([]string, error) {
mainFiles := finder.FilterFiles(files, "main.go")
return mainFiles, nil

Check failure on line 15 in internal/callgraph/finder/golangfinder/finder.go

View workflow job for this annotation

GitHub Actions / Lint

return with no blank line before (nlreturn)
}

func (f GolangFinder) FindDependencyDirs(files []string, findJars bool) ([]string, error) {
// Not needed for golang
return []string{}, nil
}

func (f GolangFinder) FindFiles(roots []string, exclusions []string) ([]string, error) {
files := make(map[string]bool)
var err error = nil

for _, root := range roots {
err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {

if err != nil {
return err
}

excluded := file.Excluded(exclusions, path)

if info.IsDir() && excluded {
return filepath.SkipDir
}

if !info.IsDir() && !excluded && filepath.Ext(path) == ".go" {
files[path] = true
}

return nil
})

if err != nil {
break
}
}

fileList := make([]string, len(files))
i := 0
for k := range files {
fileList[i] = k
i++
}

return fileList, err
}
12 changes: 12 additions & 0 deletions internal/callgraph/finder/golangfinder/finder_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package golanfinder

import (
"testing"

"github.com/debricked/cli/internal/callgraph/finder"
"github.com/stretchr/testify/assert"
)

func TestGolangFinderImplementsFinder(t *testing.T) {
assert.Implements(t, (*finder.IFinder)(nil), new(GolangFinder))
}
4 changes: 2 additions & 2 deletions internal/callgraph/finder/javafinder/finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ import (

type JavaFinder struct{}

func (f JavaFinder) FindMavenRoots(files []string) ([]string, error) {
func (f JavaFinder) FindRoots(files []string) ([]string, error) {
pomFiles := finder.FilterFiles(files, "pom.xml")
ps := PomService{}
rootFiles := ps.GetRootPomFiles(pomFiles)

return rootFiles, nil
}

func (f JavaFinder) FindJavaClassDirs(files []string, findJars bool) ([]string, error) {
func (f JavaFinder) FindDependencyDirs(files []string, findJars bool) ([]string, error) {
filteredFiles := finder.FilterFiles(files, ".*\\.class")
dirsWithClassFiles := make(map[string]bool)
for _, file := range filteredFiles {
Expand Down
8 changes: 4 additions & 4 deletions internal/callgraph/finder/javafinder/finder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,24 @@ func TestFindMavenRoots(t *testing.T) {

files := []string{"test/asd/pom.xml", "test2/pom.xml", "test2/test/asd/pom.xml", "test3/tes"}
f := JavaFinder{}
roots, err := f.FindMavenRoots(files)
roots, err := f.FindRoots(files)

assert.Nil(t, err)
assert.Len(t, roots, 0)
}

func TestFindJavaClassDirs(t *testing.T) {
func TestFindDependencyDirs(t *testing.T) {
files := []string{"test/asd/pom.xml", "test2/basd/qwe/asd.class", "test2/test/asd", "test3/tes.jar"}
f := JavaFinder{}
files, err := f.FindJavaClassDirs(files, false)
files, err := f.FindDependencyDirs(files, false)

assert.Nil(t, err)
assert.Len(t, files, 1)
gt := filepath.Join("test2", "basd", "qwe")
assert.Equal(t, files[0], gt)

files = []string{"test/asd/pom.xml", "test2/basd/qwe/asd.class", "test2/test/asd", "test3/tes.jar"}
files, err = f.FindJavaClassDirs(files, true)
files, err = f.FindDependencyDirs(files, true)

assert.Nil(t, err)
assert.Len(t, files, 2)
Expand Down
24 changes: 12 additions & 12 deletions internal/callgraph/finder/testdata/finder_mock.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
package testdata

type FinderMock struct {
FindJavaClassDirsNames []string
FindJavaClassDirsErr error
FindMavenRootsNames []string
FindMavenRootsErr error
FindFilesNames []string
FindFilesErr error
FindDependencyDirsNames []string
FindDependencyDirsErr error
FindMavenRootsNames []string
FindMavenRootsErr error
FindFilesNames []string
FindFilesErr error
}

func NewEmptyFinderMock() FinderMock {
return FinderMock{
FindJavaClassDirsNames: []string{},
FindMavenRootsNames: []string{},
FindFilesNames: []string{},
FindDependencyDirsNames: []string{},
FindMavenRootsNames: []string{},
FindFilesNames: []string{},
}
}

func (f FinderMock) FindJavaClassDirs(_ []string, _ bool) ([]string, error) {
return f.FindJavaClassDirsNames, f.FindJavaClassDirsErr
func (f FinderMock) FindDependencyDirs(_ []string, _ bool) ([]string, error) {
return f.FindDependencyDirsNames, f.FindDependencyDirsErr
}

func (f FinderMock) FindMavenRoots(_ []string) ([]string, error) {
func (f FinderMock) FindRoots(_ []string) ([]string, error) {
return f.FindMavenRootsNames, f.FindMavenRootsErr
}

Expand Down
1 change: 1 addition & 0 deletions internal/callgraph/language/golang/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# TODO: add docs to this readme on how we generate go CGs
Loading

0 comments on commit c66044f

Please sign in to comment.