Skip to content

Commit

Permalink
Merge pull request #1 from djzager/decompileImprovements
Browse files Browse the repository at this point in the history
write pom once
  • Loading branch information
pranavgaikwad authored Oct 5, 2023
2 parents 1226fc5 + 5119204 commit 7c3a9fe
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 83 deletions.
16 changes: 8 additions & 8 deletions provider/internal/java/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,15 +348,15 @@ func resolveSourcesJars(ctx context.Context, log logr.Logger, location, mavenSet
return nil
}
for _, artifact := range artifacts {
groupDirs := filepath.Join(strings.Split(artifact.groupId, ".")...)
artifactDirs := filepath.Join(strings.Split(artifact.artifactId, ".")...)
jarName := fmt.Sprintf("%s-%s.jar", artifact.artifactId, artifact.version)
groupDirs := filepath.Join(strings.Split(artifact.GroupId, ".")...)
artifactDirs := filepath.Join(strings.Split(artifact.ArtifactId, ".")...)
jarName := fmt.Sprintf("%s-%s.jar", artifact.ArtifactId, artifact.Version)
decompileJobs = append(decompileJobs, decompileJob{
artifact: artifact,
inputPath: filepath.Join(
m2Repo, groupDirs, artifactDirs, artifact.version, jarName),
m2Repo, groupDirs, artifactDirs, artifact.Version, jarName),
outputPath: filepath.Join(
m2Repo, groupDirs, artifactDirs, artifact.version, "decompiled", jarName),
m2Repo, groupDirs, artifactDirs, artifact.Version, "decompiled", jarName),
})
}
err = decompile(ctx, log, alwaysDecompileFilter(true), 10, decompileJobs, "")
Expand Down Expand Up @@ -393,9 +393,9 @@ func parseUnresolvedSources(output io.Reader) ([]javaArtifact, error) {
artifacts = append(artifacts,
javaArtifact{
packaging: JavaArchive,
artifactId: artifactId,
groupId: groupId,
version: version,
ArtifactId: artifactId,
GroupId: groupId,
Version: version,
})
}
}
Expand Down
6 changes: 3 additions & 3 deletions provider/internal/java/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ The following files have NOT been resolved:
wantList: []javaArtifact{
{
packaging: JavaArchive,
groupId: "io.konveyor.demo",
artifactId: "config-utils",
version: "1.0.0",
GroupId: "io.konveyor.demo",
ArtifactId: "config-utils",
Version: "1.0.0",
},
},
},
Expand Down
130 changes: 58 additions & 72 deletions provider/internal/java/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"archive/zip"
"bufio"
"context"
"encoding/xml"
"fmt"
"io"
"math"
Expand All @@ -14,6 +13,7 @@ import (
"path/filepath"
"strings"
"sync"
"text/template"

"github.com/go-logr/logr"
"github.com/konveyor/analyzer-lsp/engine/labels"
Expand All @@ -38,6 +38,13 @@ const javaProjectPom = `<?xml version="1.0" encoding="UTF-8"?>
</properties>
<dependencies>
{{range .}}
<dependency>
<groupId>{{.GroupId}}</groupId>
<artifactId>{{.ArtifactId}}</artifactId>
<version>{{.Version}}</version>
</dependency>
{{end}}
</dependencies>
<build>
Expand All @@ -47,9 +54,9 @@ const javaProjectPom = `<?xml version="1.0" encoding="UTF-8"?>

type javaArtifact struct {
packaging string
groupId string
artifactId string
version string
GroupId string
ArtifactId string
Version string
}

type decompileFilter interface {
Expand All @@ -65,7 +72,7 @@ func (a alwaysDecompileFilter) shouldDecompile(j javaArtifact) bool {
type excludeOpenSourceDecompileFilter map[string]*depLabelItem

func (o excludeOpenSourceDecompileFilter) shouldDecompile(j javaArtifact) bool {
matchWith := fmt.Sprintf("%s.%s", j.groupId, j.artifactId)
matchWith := fmt.Sprintf("%s.%s", j.GroupId, j.ArtifactId)
for _, r := range o {
if r.r.MatchString(matchWith) {
if _, ok := r.labels[labels.AsString(provider.DepSourceLabel, javaDepSourceOpenSource)]; ok {
Expand Down Expand Up @@ -122,8 +129,9 @@ func decompile(ctx context.Context, log logr.Logger, filter decompileFilter, wor
}
// if we just decompiled a java archive, we need to
// explode it further and copy files to project
// TODO(djzager): should we grab deps?
if job.artifact.packaging == JavaArchive && projectPath != "" {
_, _, err = explode(ctx, log, job.outputPath, projectPath)
_, _, _, err = explode(ctx, log, job.outputPath, projectPath)
if err != nil {
log.V(5).Error(err, "failed to explode decompiled jar", "path", job.inputPath)
}
Expand Down Expand Up @@ -152,20 +160,20 @@ func decompileJava(ctx context.Context, log logr.Logger, archivePath string) (ex

projectPath = filepath.Join(filepath.Dir(archivePath), "java-project")

err = createJavaProject(ctx, projectPath)
decompFilter := alwaysDecompileFilter(true)

explodedPath, decompJobs, deps, err := explode(ctx, log, archivePath, projectPath)
if err != nil {
log.Error(err, "failed to create java project", "path", projectPath)
log.Error(err, "failed to decompile archive", "path", archivePath)
return "", "", err
}
log.V(5).Info("created java project", "path", projectPath)

decompFilter := alwaysDecompileFilter(true)

explodedPath, decompJobs, err := explode(ctx, log, archivePath, projectPath)
err = createJavaProject(ctx, projectPath, deps)
if err != nil {
log.Error(err, "failed to decompile archive", "path", archivePath)
log.Error(err, "failed to create java project", "path", projectPath)
return "", "", err
}
log.V(5).Info("created java project", "path", projectPath)

err = decompile(context.TODO(), log, decompFilter, 10, decompJobs, projectPath)
if err != nil {
Expand All @@ -177,12 +185,12 @@ func decompileJava(ctx context.Context, log logr.Logger, archivePath string) (ex
}

// explode explodes the given JAR, WAR or EAR archive, generates javaArtifact struct for given archive
// and identifies all .class found recursively. returns output path, a list of decompileJob for .class & .jar files
// .jar files will only be added as decompileJob when we are unable to add them to project's pom file
func explode(ctx context.Context, log logr.Logger, archivePath, projectPath string) (string, []decompileJob, error) {
// and identifies all .class found recursively. returns output path, a list of decompileJob for .class files
func explode(ctx context.Context, log logr.Logger, archivePath, projectPath string) (string, []decompileJob, []javaArtifact, error) {
var dependencies []javaArtifact
fileInfo, err := os.Stat(archivePath)
if err != nil {
return "", nil, err
return "", nil, dependencies, err
}

// Create the destDir directory using the same permissions as the Java archive file
Expand All @@ -191,12 +199,12 @@ func explode(ctx context.Context, log logr.Logger, archivePath, projectPath stri
// make sure execute bits are set so that fernflower can decompile
err = os.MkdirAll(destDir, fileInfo.Mode()|0111)
if err != nil {
return "", nil, err
return "", nil, dependencies, err
}

archive, err := zip.OpenReader(archivePath)
if err != nil {
return "", nil, err
return "", nil, dependencies, err
}
defer archive.Close()

Expand All @@ -206,7 +214,7 @@ func explode(ctx context.Context, log logr.Logger, archivePath, projectPath stri
// Stop processing if our context is cancelled
select {
case <-ctx.Done():
return "", decompileJobs, ctx.Err()
return "", decompileJobs, dependencies, ctx.Err()
default:
}

Expand All @@ -225,23 +233,23 @@ func explode(ctx context.Context, log logr.Logger, archivePath, projectPath stri
}

if err = os.MkdirAll(filepath.Dir(filePath), f.Mode()|0111); err != nil {
return "", decompileJobs, err
return "", decompileJobs, dependencies, err
}

dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()|0111)
if err != nil {
return "", decompileJobs, err
return "", decompileJobs, dependencies, err
}
defer dstFile.Close()

archiveFile, err := f.Open()
if err != nil {
return "", decompileJobs, err
return "", decompileJobs, dependencies, err
}
defer archiveFile.Close()

if _, err := io.Copy(dstFile, archiveFile); err != nil {
return "", decompileJobs, err
return "", decompileJobs, dependencies, err
}
switch {
// when it's a .class file, decompile it into java project
Expand Down Expand Up @@ -279,43 +287,56 @@ func explode(ctx context.Context, log logr.Logger, archivePath, projectPath stri
}
// decompile web archives
case strings.HasSuffix(f.Name, WebArchive):
_, nestedJobs, err := explode(ctx, log, filePath, projectPath)
// TODO(djzager): Should we add these deps to the pom?
_, nestedJobs, _, err := explode(ctx, log, filePath, projectPath)
if err != nil {
log.Error(err, "failed to decompile file", "file", filePath)
}
decompileJobs = append(decompileJobs, nestedJobs...)
// nested JARs won't be exploded further, they will be decompiled as whole
// attempt to add nested jars as dependency before decompiling
case strings.HasSuffix(f.Name, JavaArchive):
artifact, err := addProjectDep(ctx, filepath.Join(projectPath, "pom.xml"), filePath)
dep, err := toDependency(ctx, filePath)
if err != nil {
log.Error(err, "failed to add dep", "file", filePath)
// when we fail to identify a dep we will fallback to
// decompiling it ourselves and adding as source
outputPath := filepath.Join(
filepath.Dir(filePath), fmt.Sprintf("%s-decompiled",
strings.TrimSuffix(f.Name, JavaArchive)), filepath.Base(f.Name))
// TODO(djzager): Is it possible for the
decompileJobs = append(decompileJobs, decompileJob{
inputPath: filePath,
outputPath: outputPath,
artifact: javaArtifact{
packaging: JavaArchive,
groupId: artifact.groupId,
artifactId: artifact.artifactId,
GroupId: dep.GroupId,
ArtifactId: dep.ArtifactId,
},
})
}
if (dep != javaArtifact{}) {
dependencies = append(dependencies, dep)
}
}
}

return destDir, decompileJobs, nil
return destDir, decompileJobs, dependencies, nil
}

func createJavaProject(ctx context.Context, dir string) error {
func createJavaProject(ctx context.Context, dir string, dependencies []javaArtifact) error {
tmpl := template.Must(template.New("javaProjectPom").Parse(javaProjectPom))

err := os.MkdirAll(filepath.Join(dir, "src", "main", "java"), 0755)
if err != nil {
return err
}
err = os.WriteFile(filepath.Join(dir, "pom.xml"), []byte(javaProjectPom), 0755)

pom, err := os.OpenFile(filepath.Join(dir, "pom.xml"), os.O_CREATE|os.O_WRONLY, 0755)
if err != nil {
return err
}

err = tmpl.Execute(pom, dependencies)
if err != nil {
return err
}
Expand Down Expand Up @@ -345,23 +366,7 @@ func moveFile(srcPath string, destPath string) error {
return nil
}

type project struct {
XMLName xml.Name `xml:"project"`
Dependency dependencies `xml:"dependencies"`
}

type dependencies struct {
XMLName xml.Name `xml:"dependencies"`
Dependency []dependency `xml:"dependency"`
}

type dependency struct {
GroupID string `xml:"groupId"`
ArtifactID string `xml:"artifactId"`
Version string `xml:"version"`
}

func addProjectDep(ctx context.Context, pomFile string, jarFile string) (javaArtifact, error) {
func toDependency(ctx context.Context, jarFile string) (javaArtifact, error) {
dep := javaArtifact{}
jar, err := zip.OpenReader(jarFile)
if err != nil {
Expand All @@ -388,36 +393,17 @@ func addProjectDep(ctx context.Context, pomFile string, jarFile string) (javaArt
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "version=") {
dep.version = strings.TrimSpace(strings.TrimPrefix(line, "version="))
dep.Version = strings.TrimSpace(strings.TrimPrefix(line, "version="))
} else if strings.HasPrefix(line, "artifactId=") {
dep.artifactId = strings.TrimSpace(strings.TrimPrefix(line, "artifactId="))
dep.ArtifactId = strings.TrimSpace(strings.TrimPrefix(line, "artifactId="))
} else if strings.HasPrefix(line, "groupId=") {
dep.groupId = strings.TrimSpace(strings.TrimPrefix(line, "groupId="))
dep.GroupId = strings.TrimSpace(strings.TrimPrefix(line, "groupId="))
}
}

// Read the pom
content, err := os.ReadFile(pomFile)
if err != nil {
return dep, err
}

// Unmarshal the existing pom.xml content into a Project struct
var project project
if err := xml.Unmarshal(content, &project); err != nil {
return dep, err
}
project.Dependency.Dependency = append(project.Dependency.Dependency, dependency{GroupID: dep.groupId, ArtifactID: dep.artifactId, Version: dep.version})
// Marshal the modified Project struct back to XML
updatedXML, err := xml.MarshalIndent(project, "", " ")
if err != nil {
return dep, err
}

err = os.WriteFile(pomFile, updatedXML, 0755)
return dep, err
}
}

return dep, err
return dep, fmt.Errorf("failed to construct artifact from jar")
}
Loading

0 comments on commit 7c3a9fe

Please sign in to comment.