diff --git a/src/main/java/dev/jbang/cli/Jdk.java b/src/main/java/dev/jbang/cli/Jdk.java index c21b3a013..920ab9c8e 100644 --- a/src/main/java/dev/jbang/cli/Jdk.java +++ b/src/main/java/dev/jbang/cli/Jdk.java @@ -22,6 +22,7 @@ import dev.jbang.Cache; import dev.jbang.Settings; +import dev.jbang.devkitman.JdkDistroQuery; import dev.jbang.devkitman.JdkManager; import dev.jbang.devkitman.JdkProvider; import dev.jbang.util.CommandBuffer; @@ -162,6 +163,12 @@ public static class JdkList extends BaseCommand { @Option(shortName = 'a', name = "available", hasValue = false, description = "Shows versions available for installation") boolean available; + @Option(shortName = 'P', name = "providers", hasValue = false, description = "Shows available providers") + boolean listProviders; + + @Option(shortName = 'D', name = "distros", hasValue = false, description = "Shows distributions available for installation") + boolean listDistros; + @Option(shortName = 'd', name = "show-details", aliases = { "details" }, hasValue = false, description = "Shows detailed information for each JDK (only when format=text)") boolean details; @@ -173,24 +180,58 @@ public static class JdkList extends BaseCommand { public Integer doCall() throws IOException { JdkManager jdkMan = jdkMixin.getJdkManager(); dev.jbang.devkitman.Jdk defaultJdk = jdkMan.getDefaultJdk(); - int defMajorVersion = defaultJdk != null ? defaultJdk.majorVersion() : 0; + String defVersion = defaultJdk != null ? defaultJdk.version() : ""; PrintStream out = System.out; - List jdks; + + if (listProviders) { + List providers = new ArrayList<>(jdkMan.providers()); + providers.sort(Comparator.comparing(JdkProvider::name)); + if (format == OutputFormat.json) { + Gson parser = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create(); + parser.toJson(providers, out); + } else { + out.println("Available JDK Providers:"); + providers.forEach(p -> out.println(" " + p.name())); + } + return EXIT_OK; + } else if (listDistros) { + List distros = jdkMan.listDistros(); + distros.sort(Comparator.comparing(JdkDistroQuery.JdkDistro::name)); + if (format == OutputFormat.json) { + Gson parser = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create(); + parser.toJson(distros, out); + } else { + out.println("Available JDK Distributions:"); + distros.forEach(d -> out.println(" " + d.name())); + } + return EXIT_OK; + } + + List jdkOuts; if (available) { - jdks = jdkMan.listAvailableJdks(); + List jdks = jdkMan.listAvailableJdks(); + jdkOuts = jdks.stream() + .map(jdk -> new JdkOut(jdk.id(), jdk.version(), jdk.provider().name(), + null, null, + details ? jdk.equals(defaultJdk) + : jdk.version().equals(defVersion), + jdk.tags())) + .collect(Collectors.toList()); } else { - jdks = jdkMan.listInstalledJdks(); + List jdks = jdkMan.listInstalledJdks(); + jdkOuts = jdks.stream() + .map(jdk -> new JdkOut(jdk.id(), jdk.version(), jdk.provider().name(), + jdk.home(), + jdk instanceof dev.jbang.devkitman.Jdk.LinkedJdk + ? ((dev.jbang.devkitman.Jdk.LinkedJdk) jdk).linked().id() + : null, + details ? jdk.equals(defaultJdk) + : jdk.version().equals(defVersion), + jdk.tags())) + .collect(Collectors.toList()); } - List jdkOuts = jdks.stream() - .map(jdk -> new JdkOut(jdk.id(), jdk.version(), jdk.provider().name(), - jdk.isInstalled() ? ((dev.jbang.devkitman.Jdk.InstalledJdk) jdk).home() : null, - null, - details ? jdk.equals(defaultJdk) - : jdk.majorVersion() == defMajorVersion, - jdk.tags())) - .collect(Collectors.toList()); if (!details) { - // Only keep a list of unique major versions + // Only keep a list of unique versions Set uniqueJdks = new TreeSet<>(Comparator.comparingInt(j -> j.version).reversed()); uniqueJdks.addAll(jdkOuts); jdkOuts = new ArrayList<>(uniqueJdks); @@ -207,12 +248,17 @@ public Integer doCall() throws IOException { out.print(" "); out.print(jdk.version); out.print(" ("); - out.print(jdk.fullVersion); if (details) { + out.print(jdk.fullVersion); out.print(", " + jdk.providerName + ", " + jdk.id); if (jdk.javaHomeDir != null) { out.print(", " + jdk.javaHomeDir); } + if (!jdk.tags.isEmpty()) { + out.print(", " + jdk.tags); + } + } else { + out.print(available ? jdk.id : jdk.fullVersion); } out.print(")"); if (!available) { @@ -243,13 +289,18 @@ public static class JdkUninstall extends BaseCommand { @Override public Integer doCall() throws IOException { JdkManager jdkMan = jdkMixin.getJdkManager(); + // This will first select for JDKs from providers that can actually install JDKs dev.jbang.devkitman.Jdk.InstalledJdk jdk = jdkMan.getInstalledJdk(versionOrId, - JdkProvider.Predicates.canUpdate); + JdkProvider.Predicates.canInstall); if (jdk == null) { - throw new ExitException(EXIT_INVALID_INPUT, "JDK " + versionOrId + " is not installed"); + // If necessary we select JDKs from providers that can update JDKs + jdk = jdkMan.getInstalledJdk(versionOrId, JdkProvider.Predicates.canUpdate); + if (jdk == null) { + throw new ExitException(EXIT_INVALID_INPUT, "JDK " + versionOrId + " is not installed"); + } } jdk.uninstall(); - Util.infoMsg("Uninstalled JDK:\n " + versionOrId); + Util.infoMsg("Uninstalled JDK:\n " + jdk.id()); return EXIT_OK; } } @@ -291,7 +342,7 @@ public Integer doCall() throws IOException { JdkManager jdkMan = jdkMixin.getJdkManager(); dev.jbang.devkitman.Jdk jdk = null; if (versionOrId != null && JavaUtil.isRequestedVersion(versionOrId)) { - jdk = jdkMan.getJdk(versionOrId, JdkProvider.Predicates.canUpdate); + jdk = jdkMan.getJdk(versionOrId, JdkProvider.Predicates.canInstall); } if (jdk == null || !jdk.isInstalled()) { jdk = jdkMan.getOrInstallJdk(versionOrId); diff --git a/src/test/java/dev/jbang/cli/TestJdk.java b/src/test/java/dev/jbang/cli/TestJdk.java index 5d6d54632..c66327c40 100644 --- a/src/test/java/dev/jbang/cli/TestJdk.java +++ b/src/test/java/dev/jbang/cli/TestJdk.java @@ -323,6 +323,23 @@ void testJdkInstallWithLinkingToExistingJdkPathWhenJBangManagedVersionExistsAndI assertTrue(Files.isSameFile(javaDir.toPath(), jdkPath.resolve("my11-linked").toRealPath())); } + @Test + void testJdkInstallWithLinkingAndIntegerId() { + assertThrows(IllegalArgumentException.class, + () -> checkedRun("install", "--force", "11", "/non-existent-path"), + "When providing an existing JDK path, the versionOrId parameter must be a non-integer id"); + } + + @Test + void testJdkInstallWithLinkingToExistingJBangJdkPath() { + final Path jdkPath = Settings.getCacheDir(Cache.CacheClass.jdks).resolve("11"); + initMockJdkDir(jdkPath, "11.0.14"); + + assertThrows(IllegalArgumentException.class, + () -> checkedRun("install", "my11", jdkPath.toString()), + "The provided path cannot point to a JBang managed JDK"); + } + @Test void testJdkInstallWithLinkingToExistingJdkPathWithDifferentVersion(@TempDir File javaDir) { initMockJdkDir(javaDir.toPath(), "11.0.14"); @@ -363,6 +380,30 @@ void testJdkInstallWithLinkingToExistingBrokenLink( assertTrue(Files.isSameFile(jdkOk, (jdkPath.resolve("my11-linked").toRealPath()))); } + @Test + void testJdkInstallSameVersion() throws Exception { + Arrays.asList(11).forEach(TestJdk::createMockJdk); + + CaptureResult result = checkedRun("install", "11"); + + assertThat(result.result, equalTo(SUCCESS_EXIT)); + assertThat(result.normalizedErr(), containsString("JDK is already installed")); + assertThat(result.normalizedErr(), containsString("Use --force to install anyway")); + } + + @Test + void testJdkInstallSameVersionForced() throws Exception { + Arrays.asList(11).forEach(TestJdk::createMockJdk); + Path jdkPath = Settings.getCacheDir(Cache.CacheClass.jdks); + + CaptureResult result = checkedRun("install", "--force", "11"); + + assertThat(result.result, equalTo(SUCCESS_EXIT)); + assertThat(result.normalizedErr(), containsString("Installing Mock JDK 11.1")); + assertTrue(Files.isDirectory(jdkPath.resolve("11.1"))); + assertTrue(Util.isLink(jdkPath.resolve("11"))); + } + @Test void testExistingJdkUninstall() throws Exception { int jdkVersion = 14;