diff options
Diffstat (limited to 'pkgs/development/compilers/openjdk/JavaUpdater.java')
-rw-r--r-- | pkgs/development/compilers/openjdk/JavaUpdater.java | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/pkgs/development/compilers/openjdk/JavaUpdater.java b/pkgs/development/compilers/openjdk/JavaUpdater.java new file mode 100644 index 0000000000000..32dddf2fabc7c --- /dev/null +++ b/pkgs/development/compilers/openjdk/JavaUpdater.java @@ -0,0 +1,181 @@ +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.IOException; +import java.io.PrintWriter; +import java.net.URI; +import java.net.http.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +public class JavaUpdater { + + record GitHubResult(Optional<String> latestVersion, Optional<String> next) { + } + + record JsonInfo(String repo, String version, String hash) { + public JsonInfo(JSONObject json) { + this(json.getString("repo"), json.getString("version"), json.getString("hash")); + } + + public String toJsonString(String featureVersion) { + return """ + \s "%s": { + \s "version": "%s", + \s "repo": "%s", + \s "hash": "%s" + \s }\ + """.formatted(featureVersion, version, repo, hash); + } + } + + // Parses the GitHub Link header + public static Optional<String> getNextLink(HttpHeaders headers) { + var linkHeader = headers.map().get("Link"); + if (linkHeader == null || linkHeader.isEmpty()) return null; + + var links = linkHeader.getFirst(); + var linksRegex = Pattern.compile("<(.+)>;\\s*rel=\"next\""); + return Pattern.compile(",") + .splitAsStream(links) + .map(x -> linksRegex.matcher(x).results() + .map(g -> g.group(1)) + .findFirst() + ) + .filter(Optional::isPresent) + .map(Optional::orElseThrow) + .findFirst(); + } + + // HTTP request helper, sets GITHUB_TOKEN if present + private static HttpRequest NewGithubRequest(String url) { + var token = System.getenv().get("GITHUB_TOKEN"); + var builder = HttpRequest.newBuilder() + .uri(URI.create(url)); + if (token != null) + builder.setHeader("Authorization", "Bearer " + token); + return builder.build(); + } + + private static GitHubResult getLatestTag(String url) { + var request = NewGithubRequest(url); + + var response = + HttpClient.newHttpClient().sendAsync(request, HttpResponse.BodyHandlers.ofString()) + .join(); + + var json = new JSONArray(response.body()); + + Optional<String> version = StreamSupport.stream(json.spliterator(), false) + .map(JSONObject.class::cast) + .map(x -> x.getString("name").replaceFirst("jdk-", "")) + .filter(x -> x.contains("-ga")) + .max(Comparator.comparing(Runtime.Version::parse)); + + return new GitHubResult(version, getNextLink(response.headers())); + } + + public String findNewerVersion() { + var url = Optional.of("https://api.github.com/repos/openjdk/" + getRepo() + "/tags?per_page=100"); + String version = getCurrentVersion(); + do { + GitHubResult response = getLatestTag(url.orElseThrow()); + if (response.latestVersion.isPresent() && response.latestVersion.orElseThrow().equals(version)) { + return null; + } + + String latestVersion = Stream.of(version, response.latestVersion.orElse(version)) + .max(Comparator.comparing(Runtime.Version::parse)).orElseThrow(); + + if (latestVersion != version) + return latestVersion; + + url = response.next; + } while (url.isPresent()); + return null; + } + + + private static String prettyPrint(JSONObject json) { + + Iterable<String> iterable = () -> json.keys(); + + return StreamSupport + .stream(iterable.spliterator(), false) + .sorted(Comparator.reverseOrder()) + .map(majorVersion -> (new JsonInfo(json.getJSONObject(majorVersion))).toJsonString(majorVersion)) + .collect( + Collectors.joining(",\n", "{\n", "\n}") + ); + } + + public void updateJsonInfo(String newVersion) { + try { + JSONObject json = getJsonInfo(); + var info = json.getJSONObject(featureNumber); + info.put("version", newVersion); + info.put("hash", nixHash(newVersion)); + + try (PrintWriter out = new PrintWriter(infoJsonPath)) { + out.println(prettyPrint(json)); + } + + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private String nixHash(String version) { + try { + var process = new ProcessBuilder("nix", "flake", "prefetch", + "--extra-experimental-features", "'nix-command flakes'", + "--json", "github:openjdk/" + getRepo() + "/jdk-" + version).start(); + + var json = new JSONObject(new String(process.getInputStream().readAllBytes())); + process.waitFor(); + return json.getString("hash"); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private final String featureNumber; + private final String infoJsonPath; + private final JSONObject jsonInfo; + + public String getCurrentVersion() { + return this.jsonInfo.getJSONObject(this.featureNumber).getString("version"); + } + + public String getRepo() { + return this.jsonInfo.getJSONObject(this.featureNumber).getString("repo"); + } + + public JSONObject getJsonInfo() { + try { + String infoStr = Files.readString(Path.of(this.infoJsonPath)); + return new JSONObject(infoStr); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public JavaUpdater(String featureNumber, String infoJsonPath) { + this.featureNumber = featureNumber; + this.infoJsonPath = infoJsonPath; + this.jsonInfo = getJsonInfo(); + } + + public static void main(String[] args) { + var updater = new JavaUpdater(args[0], args[1]); + String newerVersion = updater.findNewerVersion(); + if (newerVersion != null) { + updater.updateJsonInfo(newerVersion); + } + } +} |