Skip to content

Commit c761279

Browse files
eemcmullanjmleshawn-hurley
authored
✨ Get Java deps from pom/structure & disable mvn search option (#859)
Extends #852 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Improvements** * Enhanced Java dependency analysis by inferring artifact information from JAR file structure, improving detection of open source and internal dependencies. * Improved logging and error handling during Java dependency processing. * Streamlined management and assignment of dependency labels for more precise classification. * Centralized Java source resolution and dependency label initialization within the service client for better maintainability. * Added handling for unidentified embedded JARs by assigning default embedded group labels. * Introduced a new configuration option to disable Maven SHA1 lookups, providing more control over dependency resolution. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Juan Manuel Leflet Estrada <[email protected]> Signed-off-by: Emily McMullan <[email protected]> Signed-off-by: Shawn Hurley <[email protected]> Co-authored-by: Juan Manuel Leflet Estrada <[email protected]> Co-authored-by: Shawn Hurley <[email protected]>
1 parent 2cc1c29 commit c761279

File tree

5 files changed

+414
-253
lines changed

5 files changed

+414
-253
lines changed

demo-output.yaml

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,52 @@
610610
name: javax.activation.activation
611611
version: "1.1"
612612
effort: 1
613+
node-sample-rule-001:
614+
description: Testing that the node provider works - type
615+
category: potential
616+
incidents:
617+
- uri: file:///examples/nodejs/test_a.ts
618+
message: nodejs sample rule 001
619+
codeSnip: " 1 export interface Greeter {\n 2 name: string;\n 3 hello(): string;\n 4 }\n 5 \n 6 export const greeter: Greeter = {\n 7 name: \"Person1\",\n 8 hello() {\n 9 return `Hello, I'm ${this.name}`;\n10 },\n11 };\n"
620+
lineNumber: 5
621+
variables:
622+
file: file:///examples/nodejs/test_a.ts
623+
- uri: file:///examples/nodejs/test_b.ts
624+
message: nodejs sample rule 001
625+
codeSnip: " 1 import { greeter } from './test_a';\n 2 \n 3 console.log(greeter.hello());\n"
626+
lineNumber: 0
627+
variables:
628+
file: file:///examples/nodejs/test_b.ts
629+
- uri: file:///examples/nodejs/test_b.ts
630+
message: nodejs sample rule 001
631+
codeSnip: " 1 import { greeter } from './test_a';\n 2 \n 3 console.log(greeter.hello());\n"
632+
lineNumber: 2
633+
variables:
634+
file: file:///examples/nodejs/test_b.ts
635+
effort: 1
636+
node-sample-rule-002:
637+
description: Testing that the node provider works - function
638+
category: potential
639+
incidents:
640+
- uri: file:///examples/nodejs/test_a.ts
641+
message: nodejs sample rule 002
642+
codeSnip: " 1 export interface Greeter {\n 2 name: string;\n 3 hello(): string;\n 4 }\n 5 \n 6 export const greeter: Greeter = {\n 7 name: \"Person1\",\n 8 hello() {\n 9 return `Hello, I'm ${this.name}`;\n10 },\n11 };\n"
643+
lineNumber: 2
644+
variables:
645+
file: file:///examples/nodejs/test_a.ts
646+
- uri: file:///examples/nodejs/test_a.ts
647+
message: nodejs sample rule 002
648+
codeSnip: " 1 export interface Greeter {\n 2 name: string;\n 3 hello(): string;\n 4 }\n 5 \n 6 export const greeter: Greeter = {\n 7 name: \"Person1\",\n 8 hello() {\n 9 return `Hello, I'm ${this.name}`;\n10 },\n11 };\n"
649+
lineNumber: 7
650+
variables:
651+
file: file:///examples/nodejs/test_a.ts
652+
- uri: file:///examples/nodejs/test_b.ts
653+
message: nodejs sample rule 002
654+
codeSnip: " 1 import { greeter } from './test_a';\n 2 \n 3 console.log(greeter.hello());\n"
655+
lineNumber: 2
656+
variables:
657+
file: file:///examples/nodejs/test_b.ts
658+
effort: 1
613659
python-sample-rule-001:
614660
description: ""
615661
category: potential
@@ -967,52 +1013,6 @@
9671013
9681014
matchingXML: ""
9691015
effort: 1
970-
node-sample-rule-001:
971-
description: Testing that the node provider works - type
972-
category: potential
973-
incidents:
974-
- uri: file:///examples/nodejs/test_a.ts
975-
message: nodejs sample rule 001
976-
codeSnip: " 1 export interface Greeter {\n 2 name: string;\n 3 hello(): string;\n 4 }\n 5 \n 6 export const greeter: Greeter = {\n 7 name: \"Person1\",\n 8 hello() {\n 9 return `Hello, I'm ${this.name}`;\n10 },\n11 };\n"
977-
lineNumber: 5
978-
variables:
979-
file: file:///examples/nodejs/test_a.ts
980-
- uri: file:///examples/nodejs/test_b.ts
981-
message: nodejs sample rule 001
982-
codeSnip: " 1 import { greeter } from './test_a';\n 2 \n 3 console.log(greeter.hello());\n"
983-
lineNumber: 0
984-
variables:
985-
file: file:///examples/nodejs/test_b.ts
986-
- uri: file:///examples/nodejs/test_b.ts
987-
message: nodejs sample rule 001
988-
codeSnip: " 1 import { greeter } from './test_a';\n 2 \n 3 console.log(greeter.hello());\n"
989-
lineNumber: 2
990-
variables:
991-
file: file:///examples/nodejs/test_b.ts
992-
effort: 1
993-
node-sample-rule-002:
994-
description: Testing that the node provider works - function
995-
category: potential
996-
incidents:
997-
- uri: file:///examples/nodejs/test_a.ts
998-
message: nodejs sample rule 002
999-
codeSnip: " 1 export interface Greeter {\n 2 name: string;\n 3 hello(): string;\n 4 }\n 5 \n 6 export const greeter: Greeter = {\n 7 name: \"Person1\",\n 8 hello() {\n 9 return `Hello, I'm ${this.name}`;\n10 },\n11 };\n"
1000-
lineNumber: 2
1001-
variables:
1002-
file: file:///examples/nodejs/test_a.ts
1003-
- uri: file:///examples/nodejs/test_a.ts
1004-
message: nodejs sample rule 002
1005-
codeSnip: " 1 export interface Greeter {\n 2 name: string;\n 3 hello(): string;\n 4 }\n 5 \n 6 export const greeter: Greeter = {\n 7 name: \"Person1\",\n 8 hello() {\n 9 return `Hello, I'm ${this.name}`;\n10 },\n11 };\n"
1006-
lineNumber: 7
1007-
variables:
1008-
file: file:///examples/nodejs/test_a.ts
1009-
- uri: file:///examples/nodejs/test_b.ts
1010-
message: nodejs sample rule 002
1011-
codeSnip: " 1 import { greeter } from './test_a';\n 2 \n 3 console.log(greeter.hello());\n"
1012-
lineNumber: 2
1013-
variables:
1014-
file: file:///examples/nodejs/test_b.ts
1015-
effort: 1
10161016
insights:
10171017
field-rule-00001:
10181018
description: Sample field declaration rule

external-providers/java-external-provider/pkg/java_external_provider/dependency.go

Lines changed: 75 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"strings"
2020
"time"
2121

22+
"github.com/go-logr/logr"
2223
"github.com/konveyor/analyzer-lsp/engine/labels"
2324
"github.com/konveyor/analyzer-lsp/output/v1/konveyor"
2425
"github.com/konveyor/analyzer-lsp/provider"
@@ -166,7 +167,7 @@ func (p *javaServiceClient) GetDependencies(ctx context.Context) (map[uri.URI][]
166167
}
167168
ll = make(map[uri.URI][]konveyor.DepDAGItem, 0)
168169
// for binaries we only find JARs embedded in archive
169-
p.discoverDepsFromJars(p.config.DependencyPath, ll)
170+
p.discoverDepsFromJars(p.config.DependencyPath, ll, p.disableMavenSearch)
170171
if len(ll) == 0 {
171172
p.log.Info("unable to get dependencies from jars, looking for pom")
172173
pomPaths := p.discoverPoms(p.config.DependencyPath, ll)
@@ -437,7 +438,7 @@ func (p *javaServiceClient) getDependenciesForMaven(ctx context.Context) (map[ur
437438

438439
if len(m) == 0 {
439440
// grab the embedded deps
440-
p.discoverDepsFromJars(moddir, m)
441+
p.discoverDepsFromJars(moddir, m, p.disableMavenSearch)
441442
}
442443

443444
return m, nil
@@ -481,8 +482,6 @@ func (p *javaServiceClient) getDependenciesForGradle(ctx context.Context) (map[u
481482
lines := strings.Split(string(output), "\n")
482483
deps := p.parseGradleDependencyOutput(lines)
483484

484-
// TODO: do we need to separate by submodule somehow?
485-
486485
path := p.findGradleBuild()
487486
file := uri.File(path)
488487
m := map[uri.URI][]provider.DepDAGItem{}
@@ -653,25 +652,29 @@ func extractSubmoduleTrees(lines []string) [][]string {
653652
}
654653

655654
// discoverDepsFromJars walks given path to discover dependencies embedded as JARs
656-
func (p *javaServiceClient) discoverDepsFromJars(path string, ll map[uri.URI][]konveyor.DepDAGItem) {
655+
func (p *javaServiceClient) discoverDepsFromJars(path string, ll map[uri.URI][]konveyor.DepDAGItem, disableMavenSearch bool) {
657656
// for binaries we only find JARs embedded in archive
658657
w := walker{
659-
deps: ll,
660-
depToLabels: p.depToLabels,
661-
m2RepoPath: p.mvnLocalRepo,
662-
seen: map[string]bool{},
663-
initialPath: path,
658+
deps: ll,
659+
depToLabels: p.depToLabels,
660+
m2RepoPath: p.mvnLocalRepo,
661+
seen: map[string]bool{},
662+
initialPath: path,
663+
log: p.log,
664+
disableMavenSearch: disableMavenSearch,
664665
}
665666
filepath.WalkDir(path, w.walkDirForJar)
666667
}
667668

668669
type walker struct {
669-
deps map[uri.URI][]provider.DepDAGItem
670-
depToLabels map[string]*depLabelItem
671-
m2RepoPath string
672-
initialPath string
673-
seen map[string]bool
674-
pomPaths []string
670+
deps map[uri.URI][]provider.DepDAGItem
671+
depToLabels map[string]*depLabelItem
672+
m2RepoPath string
673+
initialPath string
674+
seen map[string]bool
675+
pomPaths []string
676+
log logr.Logger
677+
disableMavenSearch bool
675678
}
676679

677680
func (w *walker) walkDirForJar(path string, info fs.DirEntry, err error) error {
@@ -690,11 +693,11 @@ func (w *walker) walkDirForJar(path string, info fs.DirEntry, err error) error {
690693
d := provider.Dep{
691694
Name: info.Name(),
692695
}
693-
artifact, _ := toDependency(context.TODO(), path)
696+
artifact, _ := toDependency(context.TODO(), w.log, w.depToLabels, path, w.disableMavenSearch)
694697
if (artifact != javaArtifact{}) {
695698
d.Name = fmt.Sprintf("%s.%s", artifact.GroupId, artifact.ArtifactId)
696699
d.Version = artifact.Version
697-
d.Labels = addDepLabels(w.depToLabels, d.Name)
700+
d.Labels = addDepLabels(w.depToLabels, d.Name, artifact.foundOnline)
698701
d.ResolvedIdentifier = artifact.sha1
699702
// when we can successfully get javaArtifact from a jar
700703
// we added it to the pom and it should be in m2Repo path
@@ -727,7 +730,7 @@ func (w *walker) walkDirForJar(path string, info fs.DirEntry, err error) error {
727730
if (artifact != javaArtifact{}) {
728731
d.Name = fmt.Sprintf("%s.%s", artifact.GroupId, artifact.ArtifactId)
729732
d.Version = artifact.Version
730-
d.Labels = addDepLabels(w.depToLabels, d.Name)
733+
d.Labels = addDepLabels(w.depToLabels, d.Name, artifact.foundOnline)
731734
d.ResolvedIdentifier = artifact.sha1
732735
// when we can successfully get javaArtifact from a jar
733736
// we added it to the pom and it should be in m2Repo path
@@ -752,6 +755,7 @@ func (p *javaServiceClient) discoverPoms(pathStart string, ll map[uri.URI][]konv
752755
seen: map[string]bool{},
753756
initialPath: pathStart,
754757
pomPaths: []string{},
758+
log: p.log,
755759
}
756760
filepath.WalkDir(pathStart, w.walkDirForPom)
757761
return w.pomPaths
@@ -811,7 +815,7 @@ func (p *javaServiceClient) parseDepString(dep, localRepoPath, pomPath string) (
811815
if !strings.HasPrefix(fp, "/") {
812816
fp = "/" + fp
813817
}
814-
d.Labels = addDepLabels(p.depToLabels, d.Name)
818+
d.Labels = addDepLabels(p.depToLabels, d.Name, false)
815819
d.FileURIPrefix = fmt.Sprintf("file://%v", filepath.Dir(fp))
816820

817821
if runtime.GOOS == "windows" {
@@ -863,7 +867,9 @@ func resolveDepFilepath(d *provider.Dep, p *javaServiceClient, group string, art
863867
return fp
864868
}
865869

866-
func addDepLabels(depToLabels map[string]*depLabelItem, depName string) []string {
870+
// addDepLabels adds some labels (open-source/internal and java) to the dependencies. The openSource argument can be used
871+
// in cased it was already determined that the dependency is open source by any other means (ie by inferring the groupId)
872+
func addDepLabels(depToLabels map[string]*depLabelItem, depName string, openSource bool) []string {
867873
m := map[string]interface{}{}
868874
for _, d := range depToLabels {
869875
if d.r.Match([]byte(depName)) {
@@ -876,11 +882,20 @@ func addDepLabels(depToLabels map[string]*depLabelItem, depName string) []string
876882
for k := range m {
877883
s = append(s, k)
878884
}
879-
// if open source label is not found, qualify the dep as being internal by default
880-
if _, openSourceLabelFound :=
881-
m[labels.AsString(provider.DepSourceLabel, javaDepSourceOpenSource)]; !openSourceLabelFound {
882-
s = append(s,
883-
labels.AsString(provider.DepSourceLabel, javaDepSourceInternal))
885+
// if open source label is not found and we don't know if it's open source yet, qualify the dep as being internal by default
886+
_, openSourceLabelFound := m[labels.AsString(provider.DepSourceLabel, javaDepSourceOpenSource)]
887+
_, internalSourceLabelFound := m[labels.AsString(provider.DepSourceLabel, javaDepSourceInternal)]
888+
if openSourceLabelFound || openSource {
889+
if !openSourceLabelFound {
890+
s = append(s, labels.AsString(provider.DepSourceLabel, javaDepSourceOpenSource))
891+
}
892+
if internalSourceLabelFound {
893+
delete(m, labels.AsString(provider.DepSourceLabel, javaDepSourceInternal))
894+
}
895+
} else {
896+
if !internalSourceLabelFound {
897+
s = append(s, labels.AsString(provider.DepSourceLabel, javaDepSourceInternal))
898+
}
884899
}
885900
s = append(s, labels.AsString(provider.DepLanguageLabel, "java"))
886901
return s
@@ -924,98 +939,88 @@ func (p *javaServiceClient) parseMavenDepLines(lines []string, localRepoPath, po
924939
return []provider.DepDAGItem{}, nil
925940
}
926941

927-
// depInit loads a map of package patterns and their associated labels for easy lookup
928-
func (p *javaServiceClient) depInit() error {
929-
err := p.initOpenSourceDepLabels()
930-
if err != nil {
931-
p.log.V(5).Error(err, "failed to initialize dep labels lookup for open source packages")
932-
return err
933-
}
934-
935-
err = p.initExcludeDepLabels()
936-
if err != nil {
937-
p.log.V(5).Error(err, "failed to initialize dep labels lookup for excluded packages")
938-
return err
939-
}
940-
941-
return nil
942-
}
943-
944942
// initOpenSourceDepLabels reads user provided file that has a list of open source
945943
// packages (supports regex) and loads a map of patterns -> labels for easy lookup
946-
func (p *javaServiceClient) initOpenSourceDepLabels() error {
944+
func initOpenSourceDepLabels(log logr.Logger, providerSpecificConfig map[string]interface{}) (map[string]*depLabelItem, error) {
947945
var ok bool
948946
var v interface{}
949-
if v, ok = p.config.ProviderSpecificConfig[providerSpecificConfigOpenSourceDepListKey]; !ok {
950-
p.log.V(7).Info("Did not find open source dep list.")
951-
return nil
947+
if v, ok = providerSpecificConfig[providerSpecificConfigOpenSourceDepListKey]; !ok {
948+
log.V(7).Info("Did not find open source dep list.")
949+
return nil, nil
952950
}
953951

954952
var filePath string
955953
if filePath, ok = v.(string); !ok {
956-
return fmt.Errorf("unable to determine filePath from open source dep list")
954+
return nil, fmt.Errorf("unable to determine filePath from open source dep list")
957955
}
958956

959957
fileInfo, err := os.Stat(filePath)
960958
if err != nil {
961959
//TODO(shawn-hurley): consider wrapping error with value
962-
return err
960+
return nil, err
963961
}
964962

965963
if fileInfo.IsDir() {
966-
return fmt.Errorf("open source dep list must be a file, not a directory")
964+
return nil, fmt.Errorf("open source dep list must be a file, not a directory")
967965
}
968966

969967
file, err := os.Open(filePath)
970968
if err != nil {
971-
return err
969+
return nil, err
972970
}
973971
defer file.Close()
974-
return loadDepLabelItems(file, p.depToLabels,
975-
labels.AsString(provider.DepSourceLabel, javaDepSourceOpenSource))
972+
items, err := loadDepLabelItems(file, labels.AsString(provider.DepSourceLabel, javaDepSourceOpenSource), nil)
973+
return items, nil
976974
}
977975

978976
// initExcludeDepLabels reads user provided list of excluded packages
979977
// and initiates label lookup for them
980-
func (p *javaServiceClient) initExcludeDepLabels() error {
978+
func initExcludeDepLabels(log logr.Logger, providerSpecificConfig map[string]interface{}, depToLabels map[string]*depLabelItem) (map[string]*depLabelItem, error) {
981979
var ok bool
982980
var v interface{}
983-
if v, ok = p.config.ProviderSpecificConfig[providerSpecificConfigExcludePackagesKey]; !ok {
984-
p.log.V(7).Info("did not find exclude packages list")
985-
return nil
981+
if v, ok = providerSpecificConfig[providerSpecificConfigExcludePackagesKey]; !ok {
982+
log.V(7).Info("did not find exclude packages list")
983+
return depToLabels, nil
984+
}
985+
excludePackages, ok := v.([]string)
986+
if !ok {
987+
return nil, fmt.Errorf("%s config must be a list of packages to exclude", providerSpecificConfigExcludePackagesKey)
986988
}
987-
var excludePackages []string
988-
if excludePackages, ok = v.([]string); !ok {
989-
return fmt.Errorf("%s config must be a list of packages to exclude", providerSpecificConfigExcludePackagesKey)
989+
items, err := loadDepLabelItems(strings.NewReader(strings.Join(excludePackages, "\n")), provider.DepExcludeLabel, depToLabels)
990+
if err != nil {
991+
return nil, err
990992
}
991-
return loadDepLabelItems(strings.NewReader(
992-
strings.Join(excludePackages, "\n")), p.depToLabels, provider.DepExcludeLabel)
993+
return items, nil
993994
}
994995

995996
// loadDepLabelItems reads list of patterns from reader and appends given
996997
// label to the list of labels for the associated pattern
997-
func loadDepLabelItems(r io.Reader, depToLabels map[string]*depLabelItem, label string) error {
998+
func loadDepLabelItems(r io.Reader, label string, depToLabels map[string]*depLabelItem) (map[string]*depLabelItem, error) {
999+
depToLabelsItems := map[string]*depLabelItem{}
1000+
if depToLabels != nil {
1001+
depToLabelsItems = depToLabels
1002+
}
9981003
scanner := bufio.NewScanner(r)
9991004
for scanner.Scan() {
10001005
pattern := scanner.Text()
10011006
r, err := regexp.Compile(pattern)
10021007
if err != nil {
1003-
return fmt.Errorf("unable to create regexp for string: %v", pattern)
1008+
return nil, fmt.Errorf("unable to create regexp for string: %v", pattern)
10041009
}
10051010
//Make sure that we are not adding duplicates
1006-
if _, found := depToLabels[pattern]; !found {
1007-
depToLabels[pattern] = &depLabelItem{
1011+
if _, found := depToLabelsItems[pattern]; !found {
1012+
depToLabelsItems[pattern] = &depLabelItem{
10081013
r: r,
10091014
labels: map[string]interface{}{
10101015
label: nil,
10111016
},
10121017
}
10131018
} else {
1014-
if depToLabels[pattern].labels == nil {
1015-
depToLabels[pattern].labels = map[string]interface{}{}
1019+
if depToLabelsItems[pattern].labels == nil {
1020+
depToLabelsItems[pattern].labels = map[string]interface{}{}
10161021
}
1017-
depToLabels[pattern].labels[label] = nil
1022+
depToLabelsItems[pattern].labels[label] = nil
10181023
}
10191024
}
1020-
return nil
1025+
return depToLabelsItems, nil
10211026
}

0 commit comments

Comments
 (0)