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

🐛 use custom startup for jdtls (#749) #752

Merged
merged 1 commit into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
7 changes: 4 additions & 3 deletions external-providers/generic-external-provider/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.21 as go-builder
FROM golang:1.23 as go-builder

COPY / /analyzer-lsp

Expand All @@ -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

Expand All @@ -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

Expand Down
2 changes: 1 addition & 1 deletion external-providers/java-external-provider/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions external-providers/java-external-provider/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,18 +347,54 @@ 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 {
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",
"-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,
"-Djava.net.useSystemProxies=true",
"-configuration",
"./",
//"--jvm-arg=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:1044",
"-data",
workspace,
"-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 != "" {
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()
Expand All @@ -371,8 +407,11 @@ func (p *javaProvider) Init(ctx context.Context, log logr.Logger, config provide
}

waitErrorChannel := make(chan error)
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
err := cmd.Start()
wg.Done()
if err != nil {
cancelFunc()
returnErr = err
Expand All @@ -393,10 +432,14 @@ 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()
}()

wg.Wait()

rpc := jsonrpc2.NewConn(jsonrpc2.NewHeaderStream(stdout, stdin), log)

rpc.AddHandler(jsonrpc2.NewBackoffHandler(log))
Expand Down Expand Up @@ -966,3 +1009,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
}
2 changes: 1 addition & 1 deletion provider_container_settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"analysisMode": "full",
"providerSpecificConfig": {
"lspServerName": "generic",
"lspServerPath": "/root/go/bin/gopls",
"lspServerPath": "/usr/local/bin/gopls",
"lspServerArgs": [],
"lspServerInitializationOptions": "",

Expand Down
2 changes: 1 addition & 1 deletion provider_pod_local_settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"analysisMode": "full",
"providerSpecificConfig": {
"lspServerName": "generic",
"lspServerPath": "/root/go/bin/gopls",
"lspServerPath": "/usr/local/bin/gopls",
"lspServerArgs": [],
"lspServerInitializationOptions": "",

Expand Down
2 changes: 1 addition & 1 deletion provider_settings.json.sample
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"initConfig": [{
"location": "/analyzer-lsp/examples/golang",
"providerSpecificConfig": {
"lspServerPath": "/root/go/bin/gopls"
"lspServerPath": "/usr/local/bin/gopls"
}
}]
},
Expand Down
Loading