Skip to content

Commit

Permalink
Use analyzer input and output (#17)
Browse files Browse the repository at this point in the history
* analyzer input and output options

* build location from api and use single input path

* Update cmd/analyze.go

Co-authored-by: Pranav Gaikwad <pgaikwad@redhat.com>

---------

Co-authored-by: Pranav Gaikwad <pgaikwad@redhat.com>
  • Loading branch information
eemcmullan and pranavgaikwad authored Aug 14, 2023
1 parent 8e5490f commit 6bfbaf7
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 49 deletions.
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ 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
RUN mkdir /opt/rulesets /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
COPY --from=shim /usr/bin/windup-shim /usr/local/bin
COPY --from=rulesets /rulesets/default/generated /opt/rulesets
Expand Down
199 changes: 151 additions & 48 deletions cmd/analyze.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ package cmd

import (
"bufio"
"context"
"encoding/json"
"fmt"
"io/fs"
"io/ioutil"
"os"

"path/filepath"
"sort"
"strings"
Expand All @@ -17,7 +21,8 @@ import (
"golang.org/x/exp/slices"
)

var (
// kantra analyze flags
type analyzeCommand struct {
listSources bool
listTargets bool
skipStaticReport bool
Expand All @@ -26,86 +31,99 @@ var (
input string
output string
mode string
)
rules string
}

// analyzeCmd represents the analyze command
var analyzeCmd = &cobra.Command{
Use: "analyze",

// TODO: need better descriptions
Short: "A tool to analyze applications",
Long: ``,
PreRunE: func(cmd *cobra.Command, args []string) error {
err := Validate()
if err != nil {
return err
}
return nil
},
Run: func(cmd *cobra.Command, args []string) {
err := AnalyzeFlags()
if err != nil {
log.Errorf("Failed to execute analyzeFlags")
}
},
}
func NewAnalyzeCmd() *cobra.Command {
analyzeCmd := &analyzeCommand{}

func init() {
rootCmd.AddCommand(analyzeCmd)

analyzeCmd.PersistentFlags().BoolVar(&listSources, "list-sources", false, "List rules for available migration sources")
analyzeCmd.PersistentFlags().BoolVar(&listTargets, "list-targets", false, "List rules for available migration targets")
analyzeCmd.PersistentFlags().StringArrayVarP(&sources, "source", "s", []string{}, "Source technology to consider for analysis")
analyzeCmd.PersistentFlags().StringArrayVarP(&targets, "target", "t", []string{}, "Target technology to consider for analysis")
analyzeCmd.PersistentFlags().StringVarP(&input, "input", "i", "", "Path to application source code or a binary")
analyzeCmd.PersistentFlags().StringVarP(&output, "output", "o", "", "Path to the directory for analysis output")
analyzeCmd.PersistentFlags().BoolVar(&skipStaticReport, "skip-static-report", false, "Do not generate static report")
analyzeCmd.PersistentFlags().StringVarP(&mode, "mode", "m", "full", "Analysis mode. Must be one of 'full' or 'source-only'")
analyzeCommand := &cobra.Command{
Use: "analyze",
Short: "Analyze application source code",
PreRunE: func(cmd *cobra.Command, args []string) error {
err := analyzeCmd.Validate()
if err != nil {
return err
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
if analyzeCmd.listSources || analyzeCmd.listTargets {
err := analyzeCmd.AnalyzeFlags()
if err != nil {
log.Errorf("Failed to execute analyzeFlags", err)
return err
}
return nil
}
err := analyzeCmd.Run(cmd.Context())
if err != nil {
log.Errorf("failed to execute analyze command", err)
return err
}
return nil
},
}
analyzeCommand.Flags().BoolVar(&analyzeCmd.listSources, "list-sources", false, "List rules for available migration sources")
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().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")
analyzeCommand.Flags().StringVarP(&analyzeCmd.mode, "mode", "m", "full", "Analysis mode. Must be one of 'full' or 'source-only'")

return analyzeCommand
}

func Validate() error {
if listSources || listTargets {
func (a *analyzeCommand) Validate() error {
if a.listSources || a.listTargets {
return nil
}
stat, err := os.Stat(output)
stat, err := os.Stat(a.output)
if err != nil {
log.Errorf("failed to stat output directory %s", output)
log.Errorf("failed to stat output directory %s", a.output)
return err
}
if !stat.IsDir() {
log.Errorf("output path %s is not a directory", output)
log.Errorf("output path %s is not a directory", a.output)
return err
}
if mode != string(provider.FullAnalysisMode) &&
mode != string(provider.SourceOnlyAnalysisMode) {
if a.mode != string(provider.FullAnalysisMode) &&
a.mode != string(provider.SourceOnlyAnalysisMode) {
return fmt.Errorf("mode must be one of 'full' or 'source-only'")
}
return nil
}

func AnalyzeFlags() error {
func (a *analyzeCommand) AnalyzeFlags() error {
// reserved labels
sourceLabel := outputv1.SourceTechnologyLabel
targetLabel := outputv1.TargetTechnologyLabel

if listSources {
sourceSlice, err := readRuleFilesForLabels(sourceLabel)
if a.listSources {
sourceSlice, err := a.readRuleFilesForLabels(sourceLabel)
if err != nil {
return err
}
listOptionsFromLabels(sourceSlice, sourceLabel)
return nil
}
if listTargets {
targetsSlice, err := readRuleFilesForLabels(targetLabel)
if a.listTargets {
targetsSlice, err := a.readRuleFilesForLabels(targetLabel)
if err != nil {
return err
}
listOptionsFromLabels(targetsSlice, targetLabel)
return nil
}

return nil
}

func readRuleFilesForLabels(label string) ([]string, error) {
func (a *analyzeCommand) readRuleFilesForLabels(label string) ([]string, error) {
var labelsSlice []string
err := filepath.WalkDir(RulesetPath, walkRuleSets(RulesetPath, label, &labelsSlice))
if err != nil {
Expand All @@ -116,7 +134,6 @@ func readRuleFilesForLabels(label string) ([]string, error) {

func walkRuleSets(root string, label string, labelsSlice *[]string) fs.WalkDirFunc {
return func(path string, d fs.DirEntry, err error) error {

if !d.IsDir() {
*labelsSlice, err = readRuleFiles(path, labelsSlice, label)
if err != nil {
Expand Down Expand Up @@ -175,8 +192,94 @@ func listOptionsFromLabels(sl []string, label string) {
} else {
fmt.Println("available target technologies:")
}

for _, tech := range newSl {
fmt.Println(tech)
}
}

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")
outputFile, err := os.Create(fp)
if err != nil {
return "", err
}
defer outputFile.Close()
return fp, nil
}

// TODO: *** write all of provider settings here ***
func (a *analyzeCommand) writeProviderSettings(dir string, settingsFilePath string, sourceAppPath string) error {

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

func (a *analyzeCommand) Run(ctx context.Context) error {
if len(a.rules) == 0 {
a.rules = RulesetPath
}
outputFilePath, err := a.createOutputFile()
if err != nil {
return err
}
dir, err := os.Getwd()
if err != nil {
return err
}
settingsFilePath := filepath.Join(dir, "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)
if err != nil {
return err
}
volumes := map[string]string{
a.input: sourceAppPath,
settingsFilePath: settingsMountedPath,
outputFilePath: outputMountedPath,
}
args := []string{
fmt.Sprintf("--provider-settings=%v", settingsMountedPath),
fmt.Sprintf("--rules=%v", a.rules),
fmt.Sprintf("--output-file=%v", outputMountedPath),
}
cmd := NewContainerCommand(
ctx,
WithEntrypointArgs(args...),
WithEntrypointBin("/usr/bin/konveyor-analyzer"),
WithVolumes(volumes),
)
err = cmd.Run()
if err != nil {
return err
}
return nil
}
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ var rootCmd = &cobra.Command{

func init() {
rootCmd.AddCommand(NewOpenRewriteCommand())
rootCmd.AddCommand(NewAnalyzeCmd())
}

// Execute adds all child commands to the root command and sets flags appropriately.
Expand Down
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ import (

func main() {
cmd.Execute()

}
37 changes: 37 additions & 0 deletions settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
[
{
"name": "go",
"binaryPath": "/usr/bin/generic-external-provider",
"initConfig": [
{
"analysisMode": "full",
"providerSpecificConfig": {
"dependencyProviderPath": "/usr/bin/golang-dependency-provider",
"lspServerPath": "/root/go/bin/gopls",
"name": "go"
}
}
]
},
{
"name": "java",
"binaryPath": "/jdtls/bin/jdtls",
"initConfig": [
{
"analysisMode": "source-only",
"providerSpecificConfig": {
"bundles": "/jdtls/java-analyzer-bundle/java-analyzer-bundle.core/target/java-analyzer-bundle.core-1.0.0-SNAPSHOT.jar",
"lspServerPath": "/jdtls/bin/jdtls"
}
}
]
},
{
"name": "builtin",
"initConfig": [
{
"analysisMode": ""
}
]
}
]

0 comments on commit 6bfbaf7

Please sign in to comment.