Skip to content

Commit

Permalink
Add analyze --rules (#28)
Browse files Browse the repository at this point in the history
* add analyze --rules

* create provider settings
  • Loading branch information
eemcmullan authored Aug 17, 2023
1 parent 8b858d5 commit d1c612e
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 64 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o kantra main.go

FROM quay.io/konveyor/analyzer-lsp:latest

RUN mkdir /opt/rulesets /opt/openrewrite /opt/input /opt/input/example
RUN mkdir /opt/rulesets /opt/rulesets/input /opt/openrewrite /opt/input /opt/input/example
RUN touch /opt/input/settings.json /opt/input/output.yaml

COPY --from=builder /workspace/kantra /usr/local/bin/kantra
Expand Down
161 changes: 135 additions & 26 deletions cmd/analyze.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"encoding/json"
"fmt"
"io"
"io/fs"
"io/ioutil"
"os"
Expand All @@ -14,10 +15,13 @@ import (
"strings"

"github.com/apex/log"
"github.com/konveyor/analyzer-lsp/engine"
outputv1 "github.com/konveyor/analyzer-lsp/output/v1/konveyor"
"github.com/konveyor/analyzer-lsp/provider"
"gopkg.in/yaml.v2"

"github.com/spf13/cobra"
"golang.org/x/exp/maps"
"golang.org/x/exp/slices"
)

Expand All @@ -31,7 +35,7 @@ type analyzeCommand struct {
input string
output string
mode string
rules string
rules []string
}

// analyzeCmd represents the analyze command
Expand Down Expand Up @@ -69,7 +73,7 @@ func NewAnalyzeCmd() *cobra.Command {
analyzeCommand.Flags().BoolVar(&analyzeCmd.listTargets, "list-targets", false, "List rules for available migration targets")
analyzeCommand.Flags().StringArrayVarP(&analyzeCmd.sources, "source", "s", []string{}, "Source technology to consider for analysis")
analyzeCommand.Flags().StringArrayVarP(&analyzeCmd.targets, "target", "t", []string{}, "Target technology to consider for analysis")
analyzeCommand.Flags().StringVar(&analyzeCmd.rules, "rules", "", "Rules for analysis")
analyzeCommand.Flags().StringArrayVar(&analyzeCmd.rules, "rules", []string{}, "filename or directory containing rule files")
analyzeCommand.Flags().StringVarP(&analyzeCmd.input, "input", "i", "", "Path to application source code or a binary")
analyzeCommand.Flags().StringVarP(&analyzeCmd.output, "output", "o", "", "Path to the directory for analysis output")
analyzeCommand.Flags().BoolVar(&analyzeCmd.skipStaticReport, "skip-static-report", false, "Do not generate static report")
Expand Down Expand Up @@ -198,11 +202,7 @@ func listOptionsFromLabels(sl []string, label string) {
}

func (a *analyzeCommand) createOutputFile() (string, error) {
// if trailing '/' in given output dir, remove it
trimmedOutput := strings.TrimRight(a.output, "/")
trimmedOutput = strings.TrimRight(a.output, "\\")

fp := filepath.Join(trimmedOutput, "output.yaml")
fp := filepath.Join(a.output, "output.yaml")
outputFile, err := os.Create(fp)
if err != nil {
return "", err
Expand All @@ -211,53 +211,153 @@ func (a *analyzeCommand) createOutputFile() (string, error) {
return fp, nil
}

// TODO: *** write all of provider settings here ***
func (a *analyzeCommand) writeProviderSettings(dir string, settingsFilePath string, sourceAppPath string) error {
func (a *analyzeCommand) writeProviderSettings() error {
provConfig := []provider.Config{
{
Name: "go",
BinaryPath: "/usr/bin/generic-external-provider",
InitConfig: []provider.InitConfig{
{
Location: "/opt/input/example",
AnalysisMode: provider.FullAnalysisMode,
ProviderSpecificConfig: map[string]interface{}{
"name": "go",
"dependencyProviderPath": "/usr/bin/golang-dependency-provider",
provider.LspServerPathConfigKey: "/root/go/bin/gopls",
},
},
},
},
{
Name: "java",
BinaryPath: "/jdtls/bin/jdtls",
InitConfig: []provider.InitConfig{
{
Location: "/opt/input/example",
AnalysisMode: provider.SourceOnlyAnalysisMode,
ProviderSpecificConfig: map[string]interface{}{
"bundles": "/jdtls/java-analyzer-bundle/java-analyzer-bundle.core/target/java-analyzer-bundle.core-1.0.0-SNAPSHOT.jar",
provider.LspServerPathConfigKey: "/jdtls/bin/jdtls",
},
},
},
},
{
Name: "builtin",
InitConfig: []provider.InitConfig{
{
Location: "/opt/input/example",
AnalysisMode: "",
},
},
},
}

providerConfig := []provider.Config{}
jsonFile, err := os.Open(settingsFilePath)
jsonData, err := json.MarshalIndent(&provConfig, "", " ")
if err != nil {
return err
}
defer jsonFile.Close()
byteValue, err := ioutil.ReadAll(jsonFile)
err = json.Unmarshal(byteValue, &providerConfig)
fileName := "settings.json"
err = ioutil.WriteFile(fileName, jsonData, os.ModePerm)
if err != nil {
return err
}
for i := range providerConfig {
for init := range providerConfig[i].InitConfig {
providerConfig[i].InitConfig[init].Location = sourceAppPath
return nil
}

func (a *analyzeCommand) getRules(ruleMountedPath string, wd string, dirName string) (map[string]string, error) {
rulesMap := make(map[string]string)
rulesetNeeded := false
err := os.Mkdir(dirName, os.ModePerm)
if err != nil {
return nil, err
}
for i, r := range a.rules {
stat, err := os.Stat(r)
if err != nil {
log.Errorf("failed to stat rules %s", r)
return nil, err
}
// move rules files passed into dir to mount
if !stat.IsDir() {
rulesetNeeded = true
destFile := filepath.Join(dirName, fmt.Sprintf("rules%v.yaml", i))
err := copyFileContents(r, destFile)
if err != nil {
return nil, err
}
} else {
dirName = r
}
}
providerLocation, err := json.MarshalIndent(providerConfig, "", " ")
if rulesetNeeded {
createTempRuleSet(wd, dirName)
}
// add to volumes
rulesMap[dirName] = ruleMountedPath
return rulesMap, nil
}

func copyFileContents(src string, dst string) (err error) {
source, err := os.Open(src)
if err != nil {
return nil
}
defer source.Close()
destination, err := os.Create(dst)
if err != nil {
return err
}
err = ioutil.WriteFile(settingsFilePath, providerLocation, 0644)
defer destination.Close()
_, err = io.Copy(destination, source)
if err != nil {
return err
}
return nil
}

func (a *analyzeCommand) Run(ctx context.Context) error {
if len(a.rules) == 0 {
a.rules = RulesetPath
func createTempRuleSet(wd string, tempDirName string) error {
tempRuleSet := engine.RuleSet{
Name: "ruleset",
Description: "temp ruleset",
}
yamlData, err := yaml.Marshal(&tempRuleSet)
if err != nil {
return err
}
fileName := "ruleset.yaml"
err = ioutil.WriteFile(fileName, yamlData, os.ModePerm)
if err != nil {
return err
}
// move temp ruleset into temp dir
rulsetDefault := filepath.Join(wd, "ruleset.yaml")
destRuleSet := filepath.Join(tempDirName, "ruleset.yaml")
err = copyFileContents(rulsetDefault, destRuleSet)
if err != nil {
return err
}
defer os.Remove(rulsetDefault)
return nil
}

func (a *analyzeCommand) Run(ctx context.Context) error {
outputFilePath, err := a.createOutputFile()
if err != nil {
return err
}
dir, err := os.Getwd()
wd, err := os.Getwd()
if err != nil {
return err
}
settingsFilePath := filepath.Join(dir, "settings.json")
// TODO: clean this up
settingsFilePath := filepath.Join(wd, "settings.json")
settingsMountedPath := filepath.Join(InputPath, "settings.json")
outputMountedPath := filepath.Join(InputPath, "output.yaml")
sourceAppPath := filepath.Join(InputPath, "example")
err = a.writeProviderSettings(dir, settingsFilePath, sourceAppPath)
rulesetName := filepath.Join(RulesetPath, "input")
tempDirName := filepath.Join(wd, "tempRulesDir")
err = a.writeProviderSettings()
if err != nil {
return err
}
Expand All @@ -266,9 +366,16 @@ func (a *analyzeCommand) Run(ctx context.Context) error {
settingsFilePath: settingsMountedPath,
outputFilePath: outputMountedPath,
}
if len(a.rules) > 0 {
ruleVols, err := a.getRules(rulesetName, wd, tempDirName)
if err != nil {
return err
}
maps.Copy(volumes, ruleVols)
}
args := []string{
fmt.Sprintf("--provider-settings=%v", settingsMountedPath),
fmt.Sprintf("--rules=%v", a.rules),
fmt.Sprintf("--rules=%v", RulesetPath),
fmt.Sprintf("--output-file=%v", outputMountedPath),
}
cmd := NewContainerCommand(
Expand All @@ -281,5 +388,7 @@ func (a *analyzeCommand) Run(ctx context.Context) error {
if err != nil {
return err
}
defer os.RemoveAll(tempDirName)
defer os.Remove("settings.json")
return nil
}
37 changes: 0 additions & 37 deletions settings.json

This file was deleted.

0 comments on commit d1c612e

Please sign in to comment.