Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Containerless support for Java apps #338

Merged
merged 3 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
842 changes: 842 additions & 0 deletions cmd/analyze-bin.go

Large diffs are not rendered by default.

99 changes: 14 additions & 85 deletions cmd/analyze.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package cmd

import (
"bufio"
"bytes"
"context"
"encoding/json"
Expand All @@ -17,7 +16,6 @@ import (

"path/filepath"
"slices"
"sort"
"strings"

"github.com/devfile/alizer/pkg/apis/model"
Expand Down Expand Up @@ -70,6 +68,17 @@ var (
}
)

// analyzer container paths
const (
RulesetPath = "/opt/rulesets"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens with these paths on windows?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These paths are only used by the analyzer container, which are linux containers anyways. They aren't used in the containerless work

OpenRewriteRecipesPath = "/opt/openrewrite"
InputPath = "/opt/input"
OutputPath = "/opt/output"
XMLRulePath = "/opt/xmlrules"
ShimOutputPath = "/opt/shimoutput"
CustomRulePath = "/opt/input/rules"
)

// supported providers
const (
javaProvider = "java"
Expand All @@ -88,15 +97,6 @@ const (
ClassFile = ".class"
)

// provider config options
const (
mavenSettingsFile = "mavenSettingsFile"
lspServerPath = "lspServerPath"
lspServerName = "lspServerName"
workspaceFolders = "workspaceFolders"
dependencyProviderPath = "dependencyProviderPath"
)

// TODO add network and volume w/ interface
type ProviderInit struct {
port int
Expand Down Expand Up @@ -664,7 +664,7 @@ func (a *analyzeCommand) fetchLabels(ctx context.Context, listSources, listTarge
runModeContainer := "container"
if os.Getenv(runMode) == runModeContainer {
if listSources {
sourceSlice, err := readRuleFilesForLabels(sourceLabel)
sourceSlice, err := a.readRuleFilesForLabels(sourceLabel)
if err != nil {
a.log.Error(err, "failed to read rule labels")
return err
Expand All @@ -673,7 +673,7 @@ func (a *analyzeCommand) fetchLabels(ctx context.Context, listSources, listTarge
return nil
}
if listTargets {
targetsSlice, err := readRuleFilesForLabels(targetLabel)
targetsSlice, err := a.readRuleFilesForLabels(targetLabel)
if err != nil {
a.log.Error(err, "failed to read rule labels")
return err
Expand Down Expand Up @@ -713,7 +713,7 @@ func (a *analyzeCommand) fetchLabels(ctx context.Context, listSources, listTarge
return nil
}

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

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 = readRuleFile(path, labelsSlice, label)
if err != nil {
return err
}
}
return err
}
}

func readRuleFile(filePath string, labelsSlice *[]string, label string) ([]string, error) {
file, err := os.Open(filePath)
if err != nil {
return nil, err
}
defer file.Close()

scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanWords)

for scanner.Scan() {
// add source/target labels to slice
label := getSourceOrTargetLabel(scanner.Text(), label)
if len(label) > 0 && !slices.Contains(*labelsSlice, label) {
*labelsSlice = append(*labelsSlice, label)
}
}
if err := scanner.Err(); err != nil {
return nil, err
}
return *labelsSlice, nil
}

func getSourceOrTargetLabel(text string, label string) string {
if strings.Contains(text, label) {
return text
}
return ""
}

func listOptionsFromLabels(sl []string, label string, out io.Writer) {
var newSl []string
l := label + "="

for _, label := range sl {
newSt := strings.TrimPrefix(label, l)

if newSt != label {
newSt = strings.TrimSuffix(newSt, "+")
newSt = strings.TrimSuffix(newSt, "-")

if !slices.Contains(newSl, newSt) {
newSl = append(newSl, newSt)

}
}
}
sort.Strings(newSl)

if label == outputv1.SourceTechnologyLabel {
fmt.Fprintln(out, "available source technologies:")
} else {
fmt.Fprintln(out, "available target technologies:")
}
for _, tech := range newSl {
fmt.Fprintln(out, tech)
}
}

func (a *analyzeCommand) getDepsFolders() (map[string]string, []string) {
vols := map[string]string{}
dependencyFolders := []string{}
Expand Down
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func init() {
rootCmd.AddCommand(NewAnalyzeCmd(logger))
rootCmd.AddCommand(NewTestCommand(logger))
rootCmd.AddCommand(NewVersionCommand())
rootCmd.AddCommand(NewAnalyzeBinCmd(logger))
}

// Execute adds all child commands to the root command and sets flags appropriately.
Expand Down
10 changes: 0 additions & 10 deletions cmd/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,6 @@ import (

var Settings = &Config{}

const (
RulesetPath = "/opt/rulesets"
OpenRewriteRecipesPath = "/opt/openrewrite"
InputPath = "/opt/input"
OutputPath = "/opt/output"
XMLRulePath = "/opt/xmlrules"
ShimOutputPath = "/opt/shimoutput"
CustomRulePath = "/opt/input/rules"
)

type Config struct {
RootCommandName string `env:"CMD_NAME" default:"kantra"`
ContainerBinary string `env:"CONTAINER_TOOL" default:"/usr/bin/podman"`
Expand Down
121 changes: 121 additions & 0 deletions cmd/static-report.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package cmd

import (
"encoding/json"
"fmt"
"log"
"os"
"text/template"

"github.com/konveyor/analyzer-lsp/output/v1/konveyor"
"gopkg.in/yaml.v2"
)

// taken from https://github.com/konveyor/static-report/blob/main/analyzer-output-parser/main.go

type Application struct {
Id string `yaml:"id" json:"id"`
Name string `yaml:"name" json:"name"`
Rulesets []konveyor.RuleSet `yaml:"rulesets" json:"rulesets"`
DepItems []konveyor.DepsFlatItem `yaml:"depItems" json:"depItems"`

analysisPath string `yaml:"-" json:"-"`
depsPath string `yaml:"-" json:"-"`
}

func validateFlags(analysisOutputPaths []string, appNames []string, depsOutputs []string) ([]*Application, error) {
var applications []*Application
if len(analysisOutputPaths) == 0 {
return nil, fmt.Errorf("analysis output paths required")
}
if len(appNames) == 0 {
return nil, fmt.Errorf("application names required")
}
if len(depsOutputs) == 0 {
log.Println("dependency output path not provided, only parsing analysis output")
}
for idx, analysisPath := range analysisOutputPaths {
currApp := &Application{
Id: fmt.Sprintf("%04d", idx),
Rulesets: make([]konveyor.RuleSet, 0),
DepItems: make([]konveyor.DepsFlatItem, 0),
analysisPath: analysisPath,
}
if len(depsOutputs) > 0 {
currApp.depsPath = depsOutputs[idx]
}
currApp.Name = appNames[idx]
applications = append(applications, currApp)
}

return applications, nil
}

// loadApplications loads applications from provider config
func loadApplications(apps []*Application) error {
for _, app := range apps {
analysisReport, err := os.ReadFile(app.analysisPath)
if err != nil {
return err
}
err = yaml.Unmarshal(analysisReport, &app.Rulesets)
if err != nil {
return err
}
if app.depsPath != "" {
depsReport, err := os.ReadFile(app.depsPath)
if err != nil {
return err
}

err = yaml.Unmarshal(depsReport, &app.DepItems)
if err != nil {
return err
}
// extras on dependencies trip JSON marshaling
// we don't need them in the report, ignore them
for idx := range app.DepItems {
depItem := &app.DepItems[idx]
for _, dep := range depItem.Dependencies {
dep.Extras = make(map[string]interface{})
}
}
}
// extras on incidents trip JSON marshaling
// we don't need them in the report, ignore them
for idx := range app.Rulesets {
rs := &app.Rulesets[idx]
for _, violation := range rs.Violations {
violation.Extras = nil
for idx := range violation.Incidents {
inc := &violation.Incidents[idx]
inc.Variables = make(map[string]interface{})
}
}
}
}

return nil
}

func generateJSBundle(apps []*Application, outputPath string) error {
output, err := json.Marshal(apps)
if err != nil {
log.Fatal("failed to marshal applications", err)
}

tmpl := template.Must(template.New("").Parse(`
window["apps"] = {{.Apps}}
`))
file, err := os.Create(outputPath)
if err != nil {
log.Fatal("failed to create JS output bundle", err)
}
defer file.Close()
err = tmpl.Execute(file, struct {
Apps string
}{
Apps: string(output),
})
return err
}
Loading
Loading