Skip to content

Commit

Permalink
feat: linuxdistro jdk provider (#1826)
Browse files Browse the repository at this point in the history
* feat: liunxdistro jdk provider

adds `linuxdistro` provider which for now searches `/usr/lib/jvm` for jdks.

It is not enabled by default as it is not possible to safely determine the version and build of the jdk
present or needed to be installed if mising.

Meaning to get it user need to select it `--jdk-provider=linuxdistro` or just enable all providers `--jdk-provider=all`
on command line or run `jbang config set jdk-provider linuxdistro` to make it default for all jbang invocations.

* fix: check before assuning name is jdkprovider

* fix: make sure linux distro JDKs are valid

* chore: simplified LinuxDistroJdkProvider name and id

---------

Co-authored-by: Tako Schotanus <[email protected]>
  • Loading branch information
maxandersen and quintesse authored Sep 12, 2024
1 parent f290976 commit 8c0f8ef
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 12 deletions.
13 changes: 5 additions & 8 deletions src/main/java/dev/jbang/net/JdkManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,7 @@

import dev.jbang.Settings;
import dev.jbang.cli.ExitException;
import dev.jbang.net.jdkproviders.CurrentJdkProvider;
import dev.jbang.net.jdkproviders.DefaultJdkProvider;
import dev.jbang.net.jdkproviders.JBangJdkProvider;
import dev.jbang.net.jdkproviders.JavaHomeJdkProvider;
import dev.jbang.net.jdkproviders.PathJdkProvider;
import dev.jbang.net.jdkproviders.ScoopJdkProvider;
import dev.jbang.net.jdkproviders.SdkmanJdkProvider;
import dev.jbang.net.jdkproviders.*;
import dev.jbang.util.JavaUtil;
import dev.jbang.util.Util;

Expand All @@ -36,7 +30,7 @@ public class JdkManager {

// TODO Don't hard-code this list
public static final String[] PROVIDERS_ALL = new String[] { "current", "default", "javahome", "path", "jbang",
"sdkman", "scoop" };
"sdkman", "scoop", "linux" };
public static final String[] PROVIDERS_DEFAULT = new String[] { "current", "default", "javahome", "path", "jbang" };

public static void initProvidersByName(String... providerNames) {
Expand Down Expand Up @@ -74,6 +68,9 @@ public static void initProvidersByName(List<String> providerNames) {
case "scoop":
provider = new ScoopJdkProvider();
break;
case "linux":
provider = new LinuxJdkProvider();
break;
default:
Util.warnMsg("Unknown JDK provider: " + name);
continue;
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/dev/jbang/net/JdkProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,11 @@ default Jdk createJdk(@Nonnull String id, @Nullable Path home, @Nonnull String v

default String name() {
String nm = getClass().getSimpleName();
return nm.substring(0, nm.length() - 11).toLowerCase();
if (nm.endsWith("JdkProvider")) {
return nm.substring(0, nm.length() - 11).toLowerCase();
} else {
return nm.toLowerCase();
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ protected Path getJdkPath(@Nonnull String jdk) {
return getJdksRoot().resolve(jdk);
}

private Predicate<Path> sameJdk(Path jdkRoot) {
protected Predicate<Path> sameJdk(Path jdkRoot) {
Path release = jdkRoot.resolve("release");
return (Path p) -> {
try {
Expand All @@ -100,7 +100,7 @@ private Predicate<Path> sameJdk(Path jdkRoot) {

protected Stream<Path> listJdkPaths() throws IOException {
if (Files.isDirectory(getJdksRoot())) {
return Files.list(getJdksRoot());
return Files.list(getJdksRoot()).filter(this::acceptFolder);
}
return Stream.empty();
}
Expand All @@ -114,12 +114,16 @@ protected Path getJdksRoot() {
protected Jdk createJdk(Path home) {
String name = home.getFileName().toString();
Optional<String> version = JavaUtil.resolveJavaVersionStringFromPath(home);
if (version.isPresent()) {
if (version.isPresent() && acceptFolder(home)) {
return createJdk(jdkId(name), home, version.get());
}
return null;
}

protected boolean acceptFolder(Path jdkFolder) {
return Util.searchPath("javac", jdkFolder.resolve("bin").toString()) != null;
}

protected boolean isValidId(String id) {
return id.endsWith("-" + name());
}
Expand Down
59 changes: 59 additions & 0 deletions src/main/java/dev/jbang/net/jdkproviders/LinuxJdkProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package dev.jbang.net.jdkproviders;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

/**
* This JDK provider is intended to detects JDKs that have been installed in
* standard location of the users linux distro.
*
* For now just using `/usr/lib/jvm` as apparently fedora, debian, ubuntu and
* centos/rhel use it.
*
* If need different behavior per linux distro its intended this provider will
* adjust based on identified distro.
*
*/
public class LinuxJdkProvider extends BaseFoldersJdkProvider {
private static final Path JDKS_ROOT = Paths.get("/usr/lib/jvm");

@Nonnull
@Override
protected Path getJdksRoot() {
return JDKS_ROOT;
}

@Nullable
@Override
protected String jdkId(String name) {
return name + "-linux";
}

@Override
public boolean canUse() {
return Files.isDirectory(JDKS_ROOT);
}

@Override
protected boolean acceptFolder(Path jdkFolder) {
return super.acceptFolder(jdkFolder) && !isSameFolderSymLink(jdkFolder);
}

// Returns true if a path is a symlink to an entry in the same folder
private boolean isSameFolderSymLink(Path jdkFolder) {
Path absFolder = jdkFolder.toAbsolutePath();
if (Files.isSymbolicLink(absFolder)) {
try {
Path realPath = absFolder.toRealPath();
return Files.isSameFile(absFolder.getParent(), realPath.getParent());
} catch (IOException e) {
/* ignore */ }
}
return false;
}
}
6 changes: 6 additions & 0 deletions src/test/java/dev/jbang/cli/TestJdk.java
Original file line number Diff line number Diff line change
Expand Up @@ -451,9 +451,15 @@ private void initMockJdkDir(Path jdkPath, String version) {

private void initMockJdkDir(Path jdkPath, String version, String key) {
Util.mkdirs(jdkPath);
Path jdkBinPath = jdkPath.resolve("bin");
Util.mkdirs(jdkBinPath);
String rawJavaVersion = key + "=\"" + version + "\"";
Path release = jdkPath.resolve("release");
try {
Path javacPath = jdkBinPath.resolve("javac");
Util.writeString(javacPath, "dummy");
javacPath.toFile().setExecutable(true, true);
Util.writeString(jdkBinPath.resolve("javac.exe"), "dummy");
Util.writeString(release, rawJavaVersion);
} catch (IOException e) {
throw new RuntimeException(e);
Expand Down

0 comments on commit 8c0f8ef

Please sign in to comment.