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

Correctly detect the project runtime based on the active language server #124

Closed

Conversation

asmodeus812
Copy link

@asmodeus812 asmodeus812 commented Jul 2, 2024

The goal of this pr is to correctly resolve the runtime home directory of the jdk that a specific project is using, after that the JAVA_HOME env variable is set to that, and the appropriate maven or gradle commands can be run.

This has to be done when we call maven or gradle. The reason this is needed is pretty simple, noone has just one single runtime installed on their system, and most people work with multiple java projects configured/developed to work with different runtime versions.

For example say a user has installed the latest jdk & setup his JAVA_HOME and PATH to point to jdk21, however the user would like to run/compile the tests for an older java 8, 11 or 17 spring project.

The JAVA_HOME variable has to be set to the correct runtime for the project before any relevant maven or gradle commands are run otherwise, for more simple projects you might get by and compile it, but for more complex projects which might be using deprecated or straight up removed features between major jdk versions, you will either fail to compile the code or you will encounter a runtime exception while running the code.

By default maven always picks up JAVA_HOME, you can also configure this in the pom itself, (by adding additional toolchain and compiler plugins) by setting the path to the runtime in the compiler plugin (for your local machine) gradle is more versatile it still reads JAVA_HOME, however you can start it with -D argument or you can configure the path to the runtime in build.gradle.

Both maven and gradle have toolchain plugins which allow them to specify the java version/runtime for the project separate from the java stack on user's PATH, manually, proivde absolute path to the desired runtime on your local machine, that the project has to be run with, however in practice noone does this, locally, since most projects are microservices, they rely on pod's env.

You can see why this is kind of needed, while it is possible to provide the path to the runtime for a project, and have it be separate from JAVA_HOME (i.e the java stack which is on your PATH)

  • would not be deployeable/portable in a cluster
  • it is not usually done, since it requires user input, locally modifying the pom
  • it is specific for the user's machine, people install them in different places

The solution in this plugin is to provide the runtimes just once, either as env variables JAVA_HOME_XX, or in your lua config, not having to modify the pom for each project, locally, separately, having to add additional maven/gradle plugins to the project just to be able to specify this etc, and you would certainly forget to do that.

TL;DR - Nothing guarantees you that the java stack on user's PATH is the one a specific project requires to be compiled / depends on.

@asmodeus812 asmodeus812 force-pushed the feature/detect-project-runtimes branch from 1346e28 to d04059e Compare July 2, 2024 11:45
lua/neotest-java/build_tool/gradle.lua Outdated Show resolved Hide resolved
return
end

local config = client.config.settings.java or {}
Copy link
Owner

Choose a reason for hiding this comment

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

This is giving me this error. I suspect it is because I don't use any lsp settings.
It also happens when I have no lsp client active.

In general, neotest-java should not relay in LSPs, they should be just a complement.

 Warn 01:25:56 AM notify.warn Neotest neotest-java: .../REPOS/neotest-java/lua/neotest-java/command/runtime.lua:19: attempt to index local 'client' (a nil value) stack traceback: /home/rico/REPOS/neotest/lua/neotest/client/init.lua:89: in function '__index' .../REPOS/neotest-java/lua/neotest-java/command/runtime.lua:19: in function 'extract_runtime' .../REPOS/neotest-java/lua/neotest-java/command/runtime.lua:57: in function 'runtime' ...REPOS/neotest-java/lua/neotest-java/build_tool/maven.lua:80: in function 'get_dependencies_classpath' ...REPOS/neotest-java/lua/neotest-java/build_tool/maven.lua:97: in function 'prepare_classpath' ...-java/lua/neotest-java/command/junit_command_builder.lua:128: in function 'build' ...EPOS/neotest-java/lua/neotest-java/core/spec_builder.lua:88: in function 'build_spec' /home/rico/REPOS/neotest/lua/neotest/client/runner.lua:76: in function '_run_tree' /home/rico/REPOS/neotest/lua/neotest/client/runner.lua:65: in function [C]: in function 'xpcall' /home/rico/REPOS/neotest/lua/neotest/client/init.lua:84: in function 'run_tree' /home/rico/REPOS/neotest/lua/neotest/consumers/run.lua:73: in function 'func' /home/rico/REPOS/nvim-nio/lua/nio/tasks.lua:173: in function

lua/neotest-java/command/runtime.lua Outdated Show resolved Hide resolved
lua/neotest-java/lsp/init.lua Outdated Show resolved Hide resolved
-- table that holds the language server settings, this is mostly done for interfacing with coc.nvim, since native neovim lsp clients hold their settings in the clients table
local SETTINGS = {}

local function execute_command(command, bufnr)
Copy link
Owner

Choose a reason for hiding this comment

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

I would separate this two conditional branches into two different functions as their logic is unrelated and they are long blocks of code.

lua/neotest-java/lsp/init.lua Outdated Show resolved Hide resolved
@asmodeus812
Copy link
Author

@rcasia could you take a look again, there are a few standing questions, regarding piping, extracting the bufnr and what do we do with gradle's runtime

@rcasia rcasia linked an issue Jul 11, 2024 that may be closed by this pull request
Copy link
Owner

Choose a reason for hiding this comment

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

I would not do this job here as the lsp should know what java executable to use using vscode.java.resolveJavaExecutable like in here: https://github.com/mfussenegger/nvim-jdtls/blob/6bfd1591583b02e742fc3a2f43393c4ea3b6d3c7/lua/jdtls/util.lua#L70

@@ -66,13 +66,21 @@ require("neotest").setup({
adapters = {
require("neotest-java")({
ignore_wrapper = false, -- whether to ignore maven/gradle wrapper
java_runtimes = {
Copy link
Owner

Choose a reason for hiding this comment

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

At least nvim-jdtls and coc-java already do this work. This seems like duplicate work as lsp could be already has this setting. Or am I missing something?

if type(parsed) == "table" then
return nil
end
-- why ? there are tags which can hold multiple tags / array of tags ?
Copy link
Owner

Choose a reason for hiding this comment

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

I just wanted to retturn a non-table value, but feel free to use it to retrieve tables aswell.

@rcasia
Copy link
Owner

rcasia commented Jul 14, 2024

With those changes it looks alright and ready to merge.

@asmodeus812
Copy link
Author

With those changes it looks alright and ready to merge.

Not yet, almost. There are a few things to iron out.

@rcasia
Copy link
Owner

rcasia commented Oct 6, 2024

I will close this PR as #153 will fix the issue.

Thanks, this PR actually helped to get close to a solution.

@rcasia rcasia closed this Oct 6, 2024
@asmodeus812
Copy link
Author

@rcasia what about porting this to support coc, as the original pr ?

@rcasia
Copy link
Owner

rcasia commented Oct 7, 2024

Responded in #75 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Use correct JDK runtime for projects
2 participants