-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
65 changed files
with
3,486 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package cgexec | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"os" | ||
"os/exec" | ||
"strings" | ||
) | ||
|
||
func RunCommand(cmd *exec.Cmd, ctx IContext) error { | ||
if ctx == nil { | ||
_, err := cmd.Output() | ||
|
||
return err | ||
} | ||
|
||
// Start the external process | ||
if err := cmd.Start(); err != nil { | ||
|
||
return err | ||
} | ||
|
||
// Channel to signal when the external process completes | ||
done := make(chan error, 1) | ||
|
||
// Goroutine to wait for the process to complete | ||
go func() { | ||
err := cmd.Wait() | ||
if err != nil { | ||
args := strings.Join(cmd.Args, " ") | ||
err = fmt.Errorf("Command '%s' executed in folder '%s' gave the following error: %s", args, cmd.Dir, err.Error()) | ||
} | ||
|
||
done <- err | ||
}() | ||
|
||
select { | ||
case <-ctx.Context().Done(): | ||
|
||
if ctx.Context().Err() == context.DeadlineExceeded { | ||
// Context timeout occurred before the process started | ||
return fmt.Errorf("Timeout error: Set timeout duration for Callgraph jobs reached") | ||
} | ||
|
||
// The context was canceled, handle cancellation if needed | ||
// Send a signal to the process to terminate | ||
if cmd.Process != nil { | ||
err := cmd.Process.Signal(os.Interrupt) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
// Wait for the process to exit | ||
<-done | ||
|
||
return fmt.Errorf("Timeout error: Set timeout duration for Callgraph jobs reached") | ||
case err := <-done: | ||
// The external process completed before the context was canceled | ||
return err | ||
} | ||
} | ||
|
||
func MakeCommand(workingDir string, path string, args []string, ctx IContext) *exec.Cmd { | ||
var cmd *exec.Cmd | ||
|
||
if ctx == nil { | ||
cmd = &exec.Cmd{ | ||
Path: path, | ||
Args: args, | ||
Dir: workingDir, | ||
} | ||
} else { | ||
command := args[0] | ||
arguments := args[1:] | ||
cmd = exec.CommandContext(ctx.Context(), command, arguments...) | ||
cmd.Path = path | ||
cmd.Dir = workingDir | ||
} | ||
|
||
return cmd | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package cgexec | ||
|
||
import ( | ||
"context" | ||
"time" | ||
) | ||
|
||
type IContext interface { | ||
Context() context.Context | ||
Done() <-chan struct{} | ||
} | ||
|
||
type Context struct { | ||
ctx context.Context | ||
} | ||
|
||
func NewContext(timer int) (Context, context.CancelFunc) { | ||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timer)*time.Second) | ||
|
||
return Context{ctx}, cancel | ||
} | ||
|
||
func (c Context) Context() context.Context { | ||
return c.ctx | ||
} | ||
|
||
func (c Context) Done() <-chan struct{} { | ||
return c.ctx.Done() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package testdata | ||
|
||
import "context" | ||
|
||
type ContextMock struct { | ||
ctx context.Context | ||
} | ||
|
||
func NewContextMock() (ContextMock, context.CancelFunc) { | ||
ctx := context.Background() | ||
return ContextMock{ctx}, nil | ||
} | ||
|
||
func (c ContextMock) Context() context.Context { | ||
return c.ctx | ||
} | ||
|
||
func (c ContextMock) Done() <-chan struct{} { | ||
return c.ctx.Done() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package config | ||
|
||
type IConfig interface { | ||
Language() string | ||
Args() []string | ||
Kwargs() map[string]string | ||
} | ||
|
||
type Config struct { | ||
language string | ||
args []string | ||
kwargs map[string]string | ||
} | ||
|
||
func NewConfig(language string, args []string, kwargs map[string]string) Config { | ||
return Config{ | ||
language, | ||
args, | ||
kwargs, | ||
} | ||
} | ||
|
||
func (c Config) Language() string { | ||
return c.language | ||
} | ||
|
||
func (c Config) Args() []string { | ||
return c.args | ||
} | ||
|
||
func (c Config) Kwargs() map[string]string { | ||
return c.kwargs | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package callgraph | ||
|
||
import "github.com/debricked/cli/internal/callgraph/job" | ||
|
||
type IGeneration interface { | ||
Jobs() []job.IJob | ||
HasErr() bool | ||
} | ||
|
||
type Generation struct { | ||
jobs []job.IJob | ||
} | ||
|
||
func NewGeneration(jobs []job.IJob) Generation { | ||
return Generation{jobs} | ||
} | ||
|
||
func (g Generation) Jobs() []job.IJob { | ||
return g.jobs | ||
} | ||
|
||
func (g Generation) HasErr() bool { | ||
for _, j := range g.Jobs() { | ||
if j.Errors().HasError() { | ||
return true | ||
} | ||
} | ||
|
||
return false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package callgraph | ||
|
||
import ( | ||
"errors" | ||
"testing" | ||
|
||
"github.com/debricked/cli/internal/callgraph/job" | ||
"github.com/debricked/cli/internal/callgraph/job/testdata" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
const testDir = "dir" | ||
|
||
var testFiles = []string{"file"} | ||
|
||
func TestNewGeneration(t *testing.T) { | ||
res := NewGeneration(nil) | ||
assert.NotNil(t, res) | ||
|
||
res = NewGeneration([]job.IJob{}) | ||
assert.NotNil(t, res) | ||
|
||
res = NewGeneration([]job.IJob{testdata.NewJobMock(testDir, testFiles)}) | ||
assert.NotNil(t, res) | ||
|
||
res = NewGeneration([]job.IJob{testdata.NewJobMock(testDir, testFiles), testdata.NewJobMock(testDir, testFiles)}) | ||
assert.NotNil(t, res) | ||
} | ||
|
||
func TestJobs(t *testing.T) { | ||
res := NewGeneration(nil) | ||
assert.Empty(t, res.Jobs()) | ||
|
||
res.jobs = []job.IJob{} | ||
assert.Len(t, res.Jobs(), 0) | ||
|
||
res.jobs = []job.IJob{testdata.NewJobMock(testDir, testFiles)} | ||
assert.Len(t, res.Jobs(), 1) | ||
|
||
res.jobs = []job.IJob{testdata.NewJobMock(testDir, testFiles), testdata.NewJobMock(testDir, testFiles)} | ||
assert.Len(t, res.Jobs(), 2) | ||
} | ||
|
||
func TestHasError(t *testing.T) { | ||
res := NewGeneration(nil) | ||
assert.False(t, res.HasErr()) | ||
|
||
res.jobs = []job.IJob{testdata.NewJobMock(testDir, testFiles)} | ||
assert.False(t, res.HasErr()) | ||
|
||
jobMock := testdata.NewJobMock(testDir, testFiles) | ||
jobMock.SetErr(errors.New("error")) | ||
res.jobs = append(res.jobs, jobMock) | ||
assert.True(t, res.HasErr()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package callgraph | ||
|
||
import ( | ||
"os" | ||
|
||
"github.com/debricked/cli/internal/callgraph/cgexec" | ||
"github.com/debricked/cli/internal/callgraph/config" | ||
"github.com/debricked/cli/internal/callgraph/job" | ||
"github.com/debricked/cli/internal/callgraph/strategy" | ||
"github.com/debricked/cli/internal/io/finder" | ||
"github.com/debricked/cli/internal/tui" | ||
) | ||
|
||
type IGenerator interface { | ||
GenerateWithTimer(paths []string, exclusions []string, configs []config.IConfig, timeout int) error | ||
Generate(paths []string, exclusions []string, configs []config.IConfig, ctx cgexec.IContext) error | ||
} | ||
|
||
type Generator struct { | ||
strategyFactory strategy.IFactory | ||
scheduler IScheduler | ||
Generation IGeneration | ||
} | ||
|
||
func NewGenerator( | ||
strategyFactory strategy.IFactory, | ||
scheduler IScheduler, | ||
) *Generator { | ||
return &Generator{ | ||
strategyFactory, | ||
scheduler, | ||
Generation{}, | ||
} | ||
} | ||
|
||
func (g *Generator) GenerateWithTimer(paths []string, exclusions []string, configs []config.IConfig, timeout int) error { | ||
result := make(chan error) | ||
ctx, cancel := cgexec.NewContext(timeout) | ||
defer cancel() | ||
|
||
go func() { | ||
result <- g.Generate(paths, exclusions, configs, &ctx) | ||
}() | ||
|
||
// Wait for the result or timeout | ||
err := <-result | ||
|
||
return err | ||
} | ||
|
||
func (g *Generator) Generate(paths []string, exclusions []string, configs []config.IConfig, ctx cgexec.IContext) error { | ||
targetPath := ".debrickedTmpFolder" | ||
debrickedExclusions := []string{targetPath} | ||
exclusions = append(exclusions, debrickedExclusions...) | ||
files, _ := finder.FindFiles(paths, exclusions) | ||
finder := finder.Finder{} | ||
|
||
var jobs []job.IJob | ||
for _, config := range configs { | ||
s, strategyErr := g.strategyFactory.Make(config, files, finder, ctx) | ||
if strategyErr == nil { | ||
newJobs, err := s.Invoke() | ||
if err != nil { | ||
return err | ||
} | ||
jobs = append(jobs, newJobs...) | ||
} | ||
} | ||
|
||
generation, err := g.scheduler.Schedule(jobs, ctx) | ||
g.Generation = generation | ||
|
||
if generation.HasErr() { | ||
jobErrList := tui.NewCallgraphJobsErrorList(os.Stdout, generation.Jobs()) | ||
err = jobErrList.Render() | ||
} | ||
|
||
return err | ||
} |
Oops, something went wrong.