diff --git a/src/main/java/dev/jbang/net/JdkManager.java b/src/main/java/dev/jbang/net/JdkManager.java index 0102888b5..e5279cefa 100644 --- a/src/main/java/dev/jbang/net/JdkManager.java +++ b/src/main/java/dev/jbang/net/JdkManager.java @@ -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; @@ -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) { @@ -74,6 +68,9 @@ public static void initProvidersByName(List providerNames) { case "scoop": provider = new ScoopJdkProvider(); break; + case "linux": + provider = new LinuxJdkProvider(); + break; default: Util.warnMsg("Unknown JDK provider: " + name); continue; diff --git a/src/main/java/dev/jbang/net/JdkProvider.java b/src/main/java/dev/jbang/net/JdkProvider.java index 80c57eb5d..9a2e00715 100644 --- a/src/main/java/dev/jbang/net/JdkProvider.java +++ b/src/main/java/dev/jbang/net/JdkProvider.java @@ -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(); + } } /** diff --git a/src/main/java/dev/jbang/net/jdkproviders/BaseFoldersJdkProvider.java b/src/main/java/dev/jbang/net/jdkproviders/BaseFoldersJdkProvider.java index d680e352b..9426a14f0 100644 --- a/src/main/java/dev/jbang/net/jdkproviders/BaseFoldersJdkProvider.java +++ b/src/main/java/dev/jbang/net/jdkproviders/BaseFoldersJdkProvider.java @@ -87,7 +87,7 @@ protected Path getJdkPath(@Nonnull String jdk) { return getJdksRoot().resolve(jdk); } - private Predicate sameJdk(Path jdkRoot) { + protected Predicate sameJdk(Path jdkRoot) { Path release = jdkRoot.resolve("release"); return (Path p) -> { try { @@ -100,7 +100,7 @@ private Predicate sameJdk(Path jdkRoot) { protected Stream listJdkPaths() throws IOException { if (Files.isDirectory(getJdksRoot())) { - return Files.list(getJdksRoot()); + return Files.list(getJdksRoot()).filter(this::acceptFolder); } return Stream.empty(); } @@ -114,12 +114,16 @@ protected Path getJdksRoot() { protected Jdk createJdk(Path home) { String name = home.getFileName().toString(); Optional 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()); } diff --git a/src/main/java/dev/jbang/net/jdkproviders/LinuxJdkProvider.java b/src/main/java/dev/jbang/net/jdkproviders/LinuxJdkProvider.java new file mode 100644 index 000000000..c8dd49b84 --- /dev/null +++ b/src/main/java/dev/jbang/net/jdkproviders/LinuxJdkProvider.java @@ -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; + } +} diff --git a/src/test/java/dev/jbang/cli/TestJdk.java b/src/test/java/dev/jbang/cli/TestJdk.java index b2efc58df..0d11ed857 100644 --- a/src/test/java/dev/jbang/cli/TestJdk.java +++ b/src/test/java/dev/jbang/cli/TestJdk.java @@ -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);