Skip to content

Commit

Permalink
Add vf-cli for java (mvn) to cli
Browse files Browse the repository at this point in the history
  • Loading branch information
ProgHaj committed May 21, 2023
1 parent 89a0210 commit a63c079
Show file tree
Hide file tree
Showing 65 changed files with 3,486 additions and 26 deletions.
83 changes: 83 additions & 0 deletions internal/callgraph/cgexec/command.go
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
}
29 changes: 29 additions & 0 deletions internal/callgraph/cgexec/context.go
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()
}
20 changes: 20 additions & 0 deletions internal/callgraph/cgexec/testdata/context_mock.go
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()
}
33 changes: 33 additions & 0 deletions internal/callgraph/config/config.go
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
}
30 changes: 30 additions & 0 deletions internal/callgraph/generation.go
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
}
55 changes: 55 additions & 0 deletions internal/callgraph/generation_test.go
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())
}
79 changes: 79 additions & 0 deletions internal/callgraph/generator.go
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
}
Loading

0 comments on commit a63c079

Please sign in to comment.