Skip to content
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
11 changes: 11 additions & 0 deletions samples/listavailable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS dev.jbang:devkitman:0.4.2

import dev.jbang.devkitman.*;

class listavailable {
public static void main(String[] args) {
JdkManager jdkManager = JdkManager.create();
jdkManager.listAvailableJdks().forEach(System.out::println);
}
}
6 changes: 2 additions & 4 deletions src/main/java/dev/jbang/devkitman/Jdk.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public InstalledJdk install() {

@Override
public String toString() {
return majorVersion() + " (" + version + ", " + id + ", " + ", " + tags + "))";
return majorVersion() + " (" + version + ", " + id + ", " + tags + "))";
}
}
}
Expand Down Expand Up @@ -171,9 +171,7 @@ public int compareTo(Jdk o) {
@Override
public String toString() {
return majorVersion() + " (" + version + (provider.hasFixedVersions() ? " [fixed]" : " [dynamic]")
+ ", " + id
+ ", "
+ home + ", " + tags + "))";
+ ", " + id + ", " + home + ", " + tags + "))";
}

@NonNull
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/dev/jbang/devkitman/JdkDiscovery.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public interface JdkDiscovery {
String name();

@Nullable
JdkProvider create(Config config);
JdkProvider create(@NonNull Config config);

class Config {
@NonNull
Expand Down
163 changes: 163 additions & 0 deletions src/main/java/dev/jbang/devkitman/JdkInstallers.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package dev.jbang.devkitman;

import static dev.jbang.devkitman.util.FileUtils.deleteOnExit;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.function.BiFunction;

import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;

public class JdkInstallers {
private List<JdkInstallers.Discovery> discoveries;

private static final JdkInstallers INSTANCE = new JdkInstallers();

private JdkInstallers() {
}

public static JdkInstallers instance() {
return INSTANCE;
}

public static Discovery.Config config(JdkProvider jdkProvider, Map<String, String> properties, Path cachePath) {
return new Discovery.Config(jdkProvider, properties, cachePath);
}

/**
* Returns a list of names of all available installers.
*
* @return a list of installer names
*/
public List<String> allNames() {
LinkedHashSet<String> names = new LinkedHashSet<>();
ArrayList<String> sorted = new ArrayList<>();
for (Discovery discovery : discoveries()) {
sorted.add(discovery.name());
}
names.addAll(sorted);
return new ArrayList<>(names);
}

public List<JdkInstaller> all(Discovery.Config config) {
return parseNames(config, allNames().toArray(new String[0]));
}

public List<JdkInstaller> parseNames(Discovery.Config config, String names) {
return parseNames(config, names.split(","));
}

public List<JdkInstaller> parseNames(Discovery.Config config, String... names) {
ArrayList<JdkInstaller> installers = new ArrayList<>();
if (names != null) {
for (String nameAndConfig : names) {
JdkInstaller installer = parseName(config, nameAndConfig);
if (installer != null) {
installers.add(installer);
}
}
}
return installers;
}

public JdkInstaller parseName(Discovery.Config config, String nameAndConfig) {
return parseName(config, nameAndConfig, this::byName);
}

JdkInstaller parseName(
Discovery.Config config,
String nameAndConfig,
BiFunction<String, Discovery.Config, JdkInstaller> action) {
String[] parts = nameAndConfig.split(";");
String name = parts[0];
Discovery.Config cfg = config.copy();
for (int i = 1; i < parts.length; i++) {
String[] keyValue = parts[i].split("=");
if (keyValue.length == 2) {
cfg.properties().put(keyValue[0], keyValue[1]);
}
}
return action.apply(name, cfg);
}

public JdkInstaller byName(String name, Discovery.Config config) {
for (Discovery discovery : discoveries()) {
if (discovery.name().equals(name)) {
JdkInstaller installer = discovery.create(config);
if (installer != null) {
return installer;
}
}
}
return null;
}

private synchronized List<Discovery> discoveries() {
if (discoveries == null) {
ServiceLoader<Discovery> loader = ServiceLoader.load(Discovery.class);
discoveries = new ArrayList<>();
for (Discovery discovery : loader) {
discoveries.add(discovery);
}
discoveries.sort(Comparator.comparing(Discovery::name));
}
return discoveries;
}

public interface Discovery {
@NonNull
String name();

@Nullable
JdkInstaller create(Config config);

class Config {
@NonNull
private final JdkProvider jdkProvider;
@NonNull
private final Map<String, String> properties;
private Path cachePath;

public Config(@NonNull JdkProvider jdkProvider, @Nullable Map<String, String> properties, Path cachePath) {
this.jdkProvider = jdkProvider;
this.properties = new HashMap<>();
if (properties != null) {
this.properties.putAll(properties);
}
this.cachePath = cachePath;
}

public @NonNull JdkProvider jdkProvider() {
return jdkProvider;
}

public @NonNull Map<String, String> properties() {
return properties;
}

public @NonNull Path cachePath() {
if (cachePath == null) {
// If no cache path is set, we create a temp dir as a curtesy that will be
// deleted on exit
try {
cachePath = deleteOnExit(java.nio.file.Files.createTempDirectory("jdk-installer-cache"));
} catch (java.io.IOException e) {
throw new RuntimeException(e);
}
}
return cachePath;
}

public Config copy() {
return new Config(jdkProvider, properties, cachePath);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.function.Function;
Expand All @@ -14,6 +13,7 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.http.impl.client.HttpClientBuilder;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;

Expand All @@ -22,6 +22,7 @@

import dev.jbang.devkitman.Jdk;
import dev.jbang.devkitman.JdkInstaller;
import dev.jbang.devkitman.JdkInstallers;
import dev.jbang.devkitman.JdkProvider;
import dev.jbang.devkitman.util.*;

Expand Down Expand Up @@ -234,39 +235,21 @@ private Comparator<JdkResult> majorVersionSort() {
"Downloading JDK {0}. Be patient, this can take several minutes...",
version);
String url = foojayJdk.downloadUrl;
LOGGER.log(Level.FINE, "Downloading {0}", url);
Path jdkTmpDir = jdkDir.getParent().resolve(jdkDir.getFileName() + ".tmp");
Path jdkOldDir = jdkDir.getParent().resolve(jdkDir.getFileName() + ".old");
FileUtils.deletePath(jdkTmpDir);
FileUtils.deletePath(jdkOldDir);

try {
LOGGER.log(Level.FINE, "Downloading {0}", url);
Path jdkPkg = remoteAccessProvider.downloadFromUrl(url);

LOGGER.log(Level.INFO, "Installing JDK {0}...", version);
LOGGER.log(Level.FINE, "Unpacking to {0}", jdkDir);
UnpackUtils.unpackJdk(jdkPkg, jdkTmpDir);
if (Files.isDirectory(jdkDir)) {
Files.move(jdkDir, jdkOldDir);
} else if (Files.isSymbolicLink(jdkDir)) {
// This means we have a broken/invalid link
FileUtils.deletePath(jdkDir);
}
Files.move(jdkTmpDir, jdkDir);
FileUtils.deletePath(jdkOldDir);
JavaUtils.installJdk(jdkPkg, jdkDir);

Jdk.InstalledJdk newJdk = jdkProvider.createJdk(foojayJdk.id(), jdkDir);
if (newJdk == null) {
throw new IllegalStateException("Cannot obtain version of recently installed JDK");
}
return newJdk;
} catch (Exception e) {
FileUtils.deletePath(jdkTmpDir);
if (!Files.isDirectory(jdkDir) && Files.isDirectory(jdkOldDir)) {
try {
Files.move(jdkOldDir, jdkDir);
} catch (IOException ex) {
// Ignore
}
}
String msg = "Required Java version not possible to download or install.";
String msg = "Required Java version not possible to download or install: " + version;
LOGGER.log(Level.FINE, msg);
throw new IllegalStateException(
"Unable to download or install JDK version " + version, e);
Expand Down Expand Up @@ -369,4 +352,21 @@ static class AvailableFoojayJdk extends Jdk.AvailableJdk.Default {
this.downloadUrl = downloadUrl;
}
}

public static class Discovery implements JdkInstallers.Discovery {
@Override
public @NonNull String name() {
return "foojay";
}

@Override
public @NonNull JdkInstaller create(Config config) {
FoojayJdkInstaller installer = new FoojayJdkInstaller(config.jdkProvider());
installer.distro(config.properties().getOrDefault("distro", null));
HttpClientBuilder httpClientBuilder = NetUtils.createCachingHttpClientBuilder(config.cachePath());
RemoteAccessProvider rap = RemoteAccessProvider.createDefaultRemoteAccessProvider(httpClientBuilder);
installer.remoteAccessProvider(rap);
return installer;
}
}
}
Loading