From 32623c200ac216348908446abdb37ba03d288f10 Mon Sep 17 00:00:00 2001 From: Pranav Gaikwad Date: Thu, 12 Dec 2024 10:44:30 -0500 Subject: [PATCH 1/6] :bug: use custom startup for jdtls Signed-off-by: Pranav Gaikwad --- .../java-external-provider/go.mod | 2 +- .../java-external-provider/go.sum | 2 + .../pkg/java_external_provider/provider.go | 112 ++++++++++++++++-- 3 files changed, 107 insertions(+), 9 deletions(-) diff --git a/external-providers/java-external-provider/go.mod b/external-providers/java-external-provider/go.mod index e2c39d82..1e20719a 100644 --- a/external-providers/java-external-provider/go.mod +++ b/external-providers/java-external-provider/go.mod @@ -4,7 +4,7 @@ go 1.21 require ( github.com/go-logr/logr v1.4.1 - github.com/konveyor/analyzer-lsp v0.5.3 + github.com/konveyor/analyzer-lsp v0.6.0-alpha.2.0.20241211222333-1480e154bf3a github.com/swaggest/openapi-go v0.2.50 go.lsp.dev/uri v0.3.0 go.opentelemetry.io/otel v1.11.2 diff --git a/external-providers/java-external-provider/go.sum b/external-providers/java-external-provider/go.sum index 222c8e4c..f41e7fea 100644 --- a/external-providers/java-external-provider/go.sum +++ b/external-providers/java-external-provider/go.sum @@ -32,6 +32,8 @@ github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mO github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc= github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE= +github.com/konveyor/analyzer-lsp v0.6.0-alpha.2.0.20241211222333-1480e154bf3a h1:iGs1ucXLHe21ljIYujUT+JkiBbsgoG+mXCLBEUMSdTM= +github.com/konveyor/analyzer-lsp v0.6.0-alpha.2.0.20241211222333-1480e154bf3a/go.mod h1:l9XC3uazLba8yXoAFJWN7uBDju1s/g1Hc8TKBpE3B2U= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= diff --git a/external-providers/java-external-provider/pkg/java_external_provider/provider.go b/external-providers/java-external-provider/pkg/java_external_provider/provider.go index 65fee2ee..d8ff656f 100644 --- a/external-providers/java-external-provider/pkg/java_external_provider/provider.go +++ b/external-providers/java-external-provider/pkg/java_external_provider/provider.go @@ -347,18 +347,49 @@ func (p *javaProvider) Init(ctx context.Context, log logr.Logger, config provide } } - args := []string{ + jdtlsBasePath, err := filepath.Abs(filepath.Dir(filepath.Dir(lspServerPath))) + if err != nil { + return nil, additionalBuiltinConfig, fmt.Errorf("failed finding jdtls base path - %w", err) + } + + sharedConfigPath, err := getSharedConfigPath(jdtlsBasePath) + if err != nil { + return nil, additionalBuiltinConfig, fmt.Errorf("failed to get shared config path - %w", err) + } + + jarPath, err := findEquinoxLauncher(jdtlsBasePath) + if err != nil { + return nil, additionalBuiltinConfig, fmt.Errorf("failed to find equinox launcher - %w", err) + } + + javaExec, err := getJavaExecutable(true) + if err != nil { + return nil, additionalBuiltinConfig, fmt.Errorf("failed getting java executable - %v", err) + } + + jdtlsArgs := []string{ + "-Declipse.application=org.eclipse.jdt.ls.core.id1", "-Djava.net.useSystemProxies=true", - "-configuration", - "./", - //"--jvm-arg=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:1044", - "-data", - workspace, + "-Dosgi.bundles.defaultStartLevel=4", + "-Declipse.product=org.eclipse.jdt.ls.core.product", + "-Dosgi.checkConfiguration=true", + fmt.Sprintf("-Dosgi.sharedConfiguration.area=%s", sharedConfigPath), + "-Dosgi.sharedConfiguration.area.readOnly=true", + "-Dosgi.configuration.cascaded=true", + "-Xms1g", + "-XX:MaxRAMPercentage=70.0", + "--add-modules=ALL-SYSTEM", + "--add-opens", "java.base/java.util=ALL-UNNAMED", + "--add-opens", "java.base/java.lang=ALL-UNNAMED", + "-jar", jarPath, + "-data", workspace, + "-configuration", "./", } + if val, ok := config.ProviderSpecificConfig[JVM_MAX_MEM_INIT_OPTION].(string); ok && val != "" { - args = append(args, fmt.Sprintf("-Xmx%s", val)) + jdtlsArgs = append(jdtlsArgs, fmt.Sprintf("-Xmx%s", val)) } - cmd := exec.CommandContext(ctx, lspServerPath, args...) + cmd := exec.CommandContext(ctx, javaExec, jdtlsArgs...) stdin, err := cmd.StdinPipe() if err != nil { cancelFunc() @@ -966,3 +997,68 @@ func (p *javaProvider) BuildSettingsFile(m2CacheDir string) (settingsFile string return settingsFilePath, nil } + +func getJavaExecutable(validateJavaVersion bool) (string, error) { + javaExecutable := "java" + if javaHome, exists := os.LookupEnv("JAVA_HOME"); exists { + javaExecToTest := filepath.Join(javaHome, "bin", "java") + if runtime.GOOS == "windows" { + javaExecToTest += ".exe" + } + if _, err := os.Stat(javaExecToTest); err == nil { + javaExecutable = javaExecToTest + } + } + + if !validateJavaVersion { + return javaExecutable, nil + } + + out, err := exec.Command(javaExecutable, "-version").CombinedOutput() + if err != nil { + return "", fmt.Errorf("failed to run %s -version: %w", javaExecutable, err) + } + + re := regexp.MustCompile(`version\s"(\d+)[.\d]*"`) + matches := re.FindStringSubmatch(string(out)) + if len(matches) > 1 { + javaVersion := matches[1] + if majorVersion := javaVersion; majorVersion < "17" { + return "", errors.New("jdtls requires at least Java 17") + } + return javaExecutable, nil + } + + return "", errors.New("could not determine Java version") +} + +func findEquinoxLauncher(jdtlsBaseDir string) (string, error) { + pluginsDir := filepath.Join(jdtlsBaseDir, "plugins") + files, err := os.ReadDir(pluginsDir) + if err != nil { + return "", fmt.Errorf("failed to read plugins directory: %w", err) + } + + for _, file := range files { + if strings.HasPrefix(file.Name(), "org.eclipse.equinox.launcher_") && strings.HasSuffix(file.Name(), ".jar") { + return filepath.Join(pluginsDir, file.Name()), nil + } + } + + return "", errors.New("cannot find equinox launcher") +} + +func getSharedConfigPath(jdtlsBaseDir string) (string, error) { + var configDir string + switch runtime.GOOS { + case "linux", "freebsd": + configDir = "config_linux" + case "darwin": + configDir = "config_mac" + case "windows": + configDir = "config_win" + default: + return "", fmt.Errorf("unknown platform %s detected", runtime.GOOS) + } + return filepath.Join(jdtlsBaseDir, configDir), nil +} From 7c9264cfdcba8f276f4da0b7defe209e5e0e21af Mon Sep 17 00:00:00 2001 From: Pranav Gaikwad Date: Thu, 12 Dec 2024 11:11:37 -0500 Subject: [PATCH 2/6] :bug: minor fix Signed-off-by: Pranav Gaikwad --- .../pkg/java_external_provider/provider.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/external-providers/java-external-provider/pkg/java_external_provider/provider.go b/external-providers/java-external-provider/pkg/java_external_provider/provider.go index d8ff656f..971cf26d 100644 --- a/external-providers/java-external-provider/pkg/java_external_provider/provider.go +++ b/external-providers/java-external-provider/pkg/java_external_provider/provider.go @@ -349,27 +349,30 @@ func (p *javaProvider) Init(ctx context.Context, log logr.Logger, config provide jdtlsBasePath, err := filepath.Abs(filepath.Dir(filepath.Dir(lspServerPath))) if err != nil { + cancelFunc() return nil, additionalBuiltinConfig, fmt.Errorf("failed finding jdtls base path - %w", err) } sharedConfigPath, err := getSharedConfigPath(jdtlsBasePath) if err != nil { + cancelFunc() return nil, additionalBuiltinConfig, fmt.Errorf("failed to get shared config path - %w", err) } jarPath, err := findEquinoxLauncher(jdtlsBasePath) if err != nil { + cancelFunc() return nil, additionalBuiltinConfig, fmt.Errorf("failed to find equinox launcher - %w", err) } javaExec, err := getJavaExecutable(true) if err != nil { + cancelFunc() return nil, additionalBuiltinConfig, fmt.Errorf("failed getting java executable - %v", err) } jdtlsArgs := []string{ "-Declipse.application=org.eclipse.jdt.ls.core.id1", - "-Djava.net.useSystemProxies=true", "-Dosgi.bundles.defaultStartLevel=4", "-Declipse.product=org.eclipse.jdt.ls.core.product", "-Dosgi.checkConfiguration=true", @@ -382,8 +385,9 @@ func (p *javaProvider) Init(ctx context.Context, log logr.Logger, config provide "--add-opens", "java.base/java.util=ALL-UNNAMED", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "-jar", jarPath, - "-data", workspace, + "-Djava.net.useSystemProxies=true", "-configuration", "./", + "-data", workspace, } if val, ok := config.ProviderSpecificConfig[JVM_MAX_MEM_INIT_OPTION].(string); ok && val != "" { From 256f94ab582d0386a6fdd52b3502744c13694851 Mon Sep 17 00:00:00 2001 From: Pranav Gaikwad Date: Fri, 13 Dec 2024 09:54:11 -0500 Subject: [PATCH 3/6] :ghost: address juanma's feedback Signed-off-by: Pranav Gaikwad --- .../pkg/java_external_provider/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/external-providers/java-external-provider/pkg/java_external_provider/provider.go b/external-providers/java-external-provider/pkg/java_external_provider/provider.go index 971cf26d..f096dcbd 100644 --- a/external-providers/java-external-provider/pkg/java_external_provider/provider.go +++ b/external-providers/java-external-provider/pkg/java_external_provider/provider.go @@ -388,6 +388,7 @@ func (p *javaProvider) Init(ctx context.Context, log logr.Logger, config provide "-Djava.net.useSystemProxies=true", "-configuration", "./", "-data", workspace, + //"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:1044", } if val, ok := config.ProviderSpecificConfig[JVM_MAX_MEM_INIT_OPTION].(string); ok && val != "" { From 5b39d25411f65f6ca66c31f2e43feacd6eda2176 Mon Sep 17 00:00:00 2001 From: Pranav Gaikwad Date: Fri, 13 Dec 2024 10:00:27 -0500 Subject: [PATCH 4/6] :ghost: update go version as gopls needs it Signed-off-by: Pranav Gaikwad --- external-providers/generic-external-provider/Dockerfile | 7 ++++--- provider_container_settings.json | 2 +- provider_pod_local_settings.json | 2 +- provider_settings.json.sample | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/external-providers/generic-external-provider/Dockerfile b/external-providers/generic-external-provider/Dockerfile index bf1e3a7f..66308c5b 100644 --- a/external-providers/generic-external-provider/Dockerfile +++ b/external-providers/generic-external-provider/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.21 as go-builder +FROM golang:1.23 as go-builder COPY / /analyzer-lsp @@ -12,7 +12,7 @@ COPY external-providers/generic-external-provider/pkg/ pkg/ RUN go mod edit -replace=github.com/konveyor/analyzer-lsp=/analyzer-lsp && go mod tidy -RUN go build -o generic-external-provider main.go +RUN go build -o generic-external-provider main.go && go install golang.org/x/tools/gopls@latest FROM quay.io/konveyor/golang-dependency-provider as go-dep-provider @@ -26,8 +26,9 @@ RUN microdnf install gcc-c++ python-devel go-toolset python3-devel nodejs -y && RUN python3 -m ensurepip --upgrade RUN python3 -m pip install 'python-lsp-server>=1.8.2' RUN npm install -g typescript-language-server typescript -RUN go install golang.org/x/tools/gopls@latest + +COPY --from=go-builder /go/bin/gopls /usr/local/bin/gopls COPY --from=go-builder /generic-external-provider/generic-external-provider /usr/local/bin/generic-external-provider COPY --from=go-dep-provider /usr/local/bin/golang-dependency-provider /usr/local/bin/golang-dependency-provider diff --git a/provider_container_settings.json b/provider_container_settings.json index f68b7bd9..be04563f 100644 --- a/provider_container_settings.json +++ b/provider_container_settings.json @@ -6,7 +6,7 @@ "analysisMode": "full", "providerSpecificConfig": { "lspServerName": "generic", - "lspServerPath": "/root/go/bin/gopls", + "lspServerPath": "/usr/local/bin/gopls", "lspServerArgs": [], "lspServerInitializationOptions": "", diff --git a/provider_pod_local_settings.json b/provider_pod_local_settings.json index c1251307..6542c68d 100644 --- a/provider_pod_local_settings.json +++ b/provider_pod_local_settings.json @@ -6,7 +6,7 @@ "analysisMode": "full", "providerSpecificConfig": { "lspServerName": "generic", - "lspServerPath": "/root/go/bin/gopls", + "lspServerPath": "/usr/local/bin/gopls", "lspServerArgs": [], "lspServerInitializationOptions": "", diff --git a/provider_settings.json.sample b/provider_settings.json.sample index 356e5ae5..198f1cfa 100644 --- a/provider_settings.json.sample +++ b/provider_settings.json.sample @@ -5,7 +5,7 @@ "initConfig": [{ "location": "/analyzer-lsp/examples/golang", "providerSpecificConfig": { - "lspServerPath": "/root/go/bin/gopls" + "lspServerPath": "/usr/local/bin/gopls" } }] }, From 15784a0acd68d82ca43d2c609a2d64b1fb80960e Mon Sep 17 00:00:00 2001 From: Pranav Gaikwad Date: Fri, 13 Dec 2024 11:26:05 -0500 Subject: [PATCH 5/6] :bug: fix shutdown Signed-off-by: Pranav Gaikwad --- .../pkg/java_external_provider/provider.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/external-providers/java-external-provider/pkg/java_external_provider/provider.go b/external-providers/java-external-provider/pkg/java_external_provider/provider.go index f096dcbd..454ab098 100644 --- a/external-providers/java-external-provider/pkg/java_external_provider/provider.go +++ b/external-providers/java-external-provider/pkg/java_external_provider/provider.go @@ -407,7 +407,10 @@ func (p *javaProvider) Init(ctx context.Context, log logr.Logger, config provide } waitErrorChannel := make(chan error) + wg := &sync.WaitGroup{} + wg.Add(1) go func() { + defer wg.Done() err := cmd.Start() if err != nil { cancelFunc() @@ -429,10 +432,16 @@ func (p *javaProvider) Init(ctx context.Context, log logr.Logger, config provide stdout.Close() } }() + // This will close the go routine above when wait has completed. go func() { waitErrorChannel <- cmd.Wait() }() + + go func() { + wg.Wait() + }() + rpc := jsonrpc2.NewConn(jsonrpc2.NewHeaderStream(stdout, stdin), log) rpc.AddHandler(jsonrpc2.NewBackoffHandler(log)) From 275fdf9683764e1a85664c70dc8bb137fd9be637 Mon Sep 17 00:00:00 2001 From: Pranav Gaikwad Date: Fri, 13 Dec 2024 12:14:35 -0500 Subject: [PATCH 6/6] :bug: minor fix to wait() Signed-off-by: Pranav Gaikwad --- .../pkg/java_external_provider/provider.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/external-providers/java-external-provider/pkg/java_external_provider/provider.go b/external-providers/java-external-provider/pkg/java_external_provider/provider.go index 454ab098..85ba0197 100644 --- a/external-providers/java-external-provider/pkg/java_external_provider/provider.go +++ b/external-providers/java-external-provider/pkg/java_external_provider/provider.go @@ -410,8 +410,8 @@ func (p *javaProvider) Init(ctx context.Context, log logr.Logger, config provide wg := &sync.WaitGroup{} wg.Add(1) go func() { - defer wg.Done() err := cmd.Start() + wg.Done() if err != nil { cancelFunc() returnErr = err @@ -438,9 +438,7 @@ func (p *javaProvider) Init(ctx context.Context, log logr.Logger, config provide waitErrorChannel <- cmd.Wait() }() - go func() { - wg.Wait() - }() + wg.Wait() rpc := jsonrpc2.NewConn(jsonrpc2.NewHeaderStream(stdout, stdin), log)