ppalaga commented on code in PR #23333:
URL: https://github.com/apache/camel/pull/23333#discussion_r3275683276
##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/QuarkusHelper.java:
##########
@@ -16,150 +16,577 @@
*/
package org.apache.camel.dsl.jbang.core.common;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.math.BigInteger;
import java.net.URI;
+import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.attribute.FileTime;
import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.Comparator;
import java.util.List;
-import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
+import java.util.Properties;
import java.util.function.BiConsumer;
-import java.util.function.BinaryOperator;
import java.util.function.Function;
-import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.w3c.dom.Document;
+
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import
org.apache.camel.dsl.jbang.core.commands.version.VersionList.CamelAndRuntimeVersions;
+import org.apache.camel.tooling.maven.MavenArtifact;
+import org.apache.camel.tooling.maven.MavenDownloader;
+import org.apache.camel.tooling.maven.MavenGav;
+import org.apache.camel.util.json.DeserializationException;
import org.apache.camel.util.json.JsonArray;
import org.apache.camel.util.json.JsonObject;
import org.apache.camel.util.json.Jsoner;
+import org.apache.maven.artifact.versioning.ComparableVersion;
+
+import static
org.apache.camel.dsl.jbang.core.common.CamelJBangConstants.QUARKUS_EXTENSION_REGISTRY_BASE_URI;
+import static
org.apache.camel.dsl.jbang.core.common.CamelJBangConstants.QUARKUS_GROUP_ID;
+import static
org.apache.camel.dsl.jbang.core.common.CamelJBangConstants.QUARKUS_VERSION;
/**
* Helper for resolving Quarkus platform information from the Quarkus registry.
*/
public final class QuarkusHelper {
public static final String QUARKUS_PLATFORM_URL_PROPERTY =
"camel.jbang.quarkus.platform.url";
- public static final String DEFAULT_QUARKUS_PLATFORM_URL =
RuntimeType.QUARKUS_EXTENSION_REGISTRY_BASE_URL
- +
(RuntimeType.QUARKUS_EXTENSION_REGISTRY_BASE_URL.endsWith("/")
- ? "" :
"/")
- +
"client/platforms";
private QuarkusHelper() {
}
- /**
- * Returns the Quarkus platform registry URL, honoring the system property
{@value #QUARKUS_PLATFORM_URL_PROPERTY}
- * if set.
- */
- public static String getQuarkusPlatformUrl() {
- return System.getProperty(QUARKUS_PLATFORM_URL_PROPERTY,
DEFAULT_QUARKUS_PLATFORM_URL);
+ public static Stream<CamelAndRuntimeVersions> listQuarkusPlatformVersions(
+ Function<MavenGav, MavenArtifact> mavenResolver,
+ boolean download,
+ String quarkusExtensionRegistryBaseUri,
+ boolean fresh) {
+ JsonArray streams =
fetchPlatformStreams(quarkusExtensionRegistryBaseUri, download, fresh,
registriesDir());
+ if (streams == null || streams.isEmpty()) {
+ return Stream.empty();
+ }
+ return listQuarkusPlatformVersions(streams, mavenResolver);
}
- /**
- * Resolves the actual Quarkus platform version for each row by fetching
the Quarkus platform registry and matching
- * the Camel Quarkus major.minor version against stream IDs.
- *
- * @param rows the list of rows to enrich with Quarkus
platform versions
- * @param runtimeVersionFunc function to extract the runtime (Camel
Quarkus) version from a row
- * @param quarkusVersionSetter consumer to set the resolved Quarkus
platform version on a row
- */
- public static <T> void resolveQuarkusPlatformVersions(
- List<T> rows,
- Function<T, String> runtimeVersionFunc,
- BiConsumer<T, String> quarkusVersionSetter) {
-
- JsonArray streams = fetchPlatformStreams();
- if (streams == null) {
- return;
+ private static Path registriesDir() {
+ final Path regDir =
CommandLineHelper.getCamelDir().resolve("quarkus-extension-registries");
+ try {
+ if (!Files.isDirectory(regDir)) {
+ Files.createDirectories(regDir);
+ }
+ return regDir
+ .toRealPath(LinkOption.NOFOLLOW_LINKS);
+ } catch (IOException e) {
+ throw new UncheckedIOException("Could not get real path for " +
regDir, e);
}
+ }
- // keep the row with the highest runtime version per major.minor stream
- BinaryOperator<T> keepLatest = (a, b) -> VersionHelper.compare(
- runtimeVersionFunc.apply(a), runtimeVersionFunc.apply(b)) >= 0
? a : b;
-
- Map<String, T> latestPerStream = rows.stream()
- .filter(row -> runtimeVersionFunc.apply(row) != null)
- .collect(Collectors.toMap(
- row ->
VersionHelper.getMajorMinorVersion(runtimeVersionFunc.apply(row)),
- Function.identity(),
- keepLatest));
-
- // match each major.minor against registry streams and set the quarkus
version
- latestPerStream.forEach((majorMinor, row) ->
findStreamVersion(streams, majorMinor, "quarkus-core-version")
- .ifPresent(version -> quarkusVersionSetter.accept(row,
version)));
+ static Stream<CamelAndRuntimeVersions> listQuarkusPlatformVersions(
+ JsonArray streams,
+ Function<MavenGav, MavenArtifact> mavenResolver) {
+ return streams.stream()
+ .map(s -> (JsonObject) s)
+ .map(PlatformStream::of)
+ .flatMap(platformStream ->
platformStream.platformReleases().stream())
+ .map(platformRelease -> {
+ List<String> versions
+ =
platformRelease.findManagedVersions(mavenResolver, Ga.CAMEL_DIRECT,
Ga.CAMEL_QUARKUS_DIRECT);
+ return new CamelAndRuntimeVersions(
+ versions.get(0),
platformRelease.quarkusCamelBomGav.getVersion(), versions.get(1));
+ });
}
/**
- * Resolves the Quarkus platform BOM version by matching the build-time
version's major.minor against the Quarkus
- * platform registry.
+ * Finds the newest Quarkus platform BOM {@code g:a:v} using the same or
newer {@code major.minor} Camel version as
+ * the specified {@code camelVersion} by searching in Quarkus platform
registry or returns the specified
+ * {@code buildTimeQuarkusVersion} if no compatible Platform version can
be found.
* <p>
* This is used by export/run commands to query the registry for the
correct platform BOM version instead of using
* the build-time constant. The registry may have a newer compatible
version.
*
- * @param buildTimeVersion the build-time Quarkus version (e.g.,
"3.15.7.something")
- * @return the resolved platform BOM version from the
registry, or the original buildTimeVersion if
- * resolution fails
+ * @param camelVersion if specified, the value of
{@code --camel-version} CLI parameter or the
+ * Camel version of the currently
running camel-jbang. Must not be
+ * {@code null}
+ * @param quarkusExtensionRegistryBaseUri
+ * @param downloader A {@link MavenDownloader} to
use for accessing
+ * @return the resolved platform BOM
version from the registry, or the original
+ * buildTimeVersion if resolution
fails
*/
- public static String resolveQuarkusPlatformVersion(String
buildTimeVersion) {
- if (buildTimeVersion == null) {
- return null;
+ public static QuarkusPlatformBom findQuarkusPlatformBom(
+ String camelVersion,
+ Function<MavenGav, MavenArtifact> mavenResolver,
+ boolean download,
+ String quarkusExtensionRegistryBaseUri,
+ boolean fresh) {
+ if (camelVersion == null) {
+ camelVersion = RuntimeType.main.version();
}
- JsonArray streams = fetchPlatformStreams();
- if (streams == null) {
- return buildTimeVersion;
+ JsonArray streams =
fetchPlatformStreams(quarkusExtensionRegistryBaseUri, download, fresh,
registriesDir());
+ if (streams == null || streams.isEmpty()) {
+ return null;
}
+ Optional<QuarkusPlatformBom> resolved
+ = findPlatformBom(streams, new MajorMinor(camelVersion),
mavenResolver, quarkusExtensionRegistryBaseUri);
+ return resolved.orElse(null);
+ }
- String majorMinor =
VersionHelper.getMajorMinorVersion(buildTimeVersion);
- Optional<String> resolved = findStreamVersion(streams, majorMinor,
"version");
- return resolved.orElse(buildTimeVersion);
+ public static String resolveCamelVersionFromQuarkusCamelBom(
+ MavenGav quarkusCamelBom, Function<MavenGav, MavenArtifact>
mavenResolver) {
+ Path file = mavenResolver.apply(quarkusCamelBom).getFile().toPath();
+ XPath xPath = XPathFactory.newInstance().newXPath();
+ String expr = managedDependencyVersionXPath("org.apache.camel",
"camel-direct");
+ try (InputStream in = Files.newInputStream(file)) {
+ String camelVersion = (String) xPath.evaluate(expr, new
InputSource(in), XPathConstants.STRING);
+ return camelVersion;
+ } catch (IOException e) {
+ throw new UncheckedIOException("Could not read " + file, e);
+ } catch (XPathExpressionException e) {
+ throw new RuntimeException("Could not evaluate " + expr + " on
file " + file);
+ }
}
/**
* Fetches the platform streams array from the Quarkus platform registry.
*
* @return the streams JsonArray, or null if the registry is unreachable
or the response is invalid
*/
- private static JsonArray fetchPlatformStreams() {
+ static JsonArray fetchPlatformStreams(
+ String quarkusExtensionRegistryBaseUri,
+ boolean download,
+ boolean fresh,
+ Path registriesDir) {
+ final String quarkusPlatformUrl = quarkusExtensionRegistryBaseUri
+ + "/client/platforms/all"
+ +
(quarkusExtensionRegistryBaseUri.startsWith("file://") ? ".json" : "");
try {
+ final URI uri = new URI(quarkusPlatformUrl);
+ if (uri.getScheme().equals("file")) {
+ return deserialize(Files.readString(Path.of(uri)));
+ }
+
+ if (fresh && !download) {
+ throw new IllegalStateException(
+ "Options --fresh and --download=false contradict each
other."
+ + " You may want to remove one
of them or pass and explicit --quarkus-version if the current command supports
it");
+ }
+
+ if (!fresh || !download) {
+ Path cacheFile = cacheFile(uri, registriesDir);
+ /* Check whether there is a cached document */
+ if (Files.isRegularFile(cacheFile)) {
+
+ if (!download || updatedToday(cacheFile)) {
+ /* We are in offline mode or the file was already
updated today */
+ return deserialize(Files.readString(cacheFile));
+ }
+ }
+ }
+
HttpClient hc = HttpClient.newHttpClient();
HttpResponse<String> res = hc.send(
- HttpRequest.newBuilder(new URI(getQuarkusPlatformUrl()))
+ HttpRequest.newBuilder(uri)
.timeout(Duration.ofSeconds(2))
.build(),
HttpResponse.BodyHandlers.ofString());
if (res.statusCode() == 200) {
- JsonObject json = (JsonObject) Jsoner.deserialize(res.body());
- JsonArray platforms = json.getCollection("platforms");
- if (platforms == null || platforms.isEmpty()) {
- return null;
- }
- JsonObject platform = platforms.getMap(0);
- return platform.getCollection("streams");
+ final String jsonBody = res.body();
+
+ /* Refresh the cached file */
+ Path cacheFile = cacheFile(uri, registriesDir);
+ Files.createDirectories(cacheFile.getParent());
+ Files.writeString(cacheFile, jsonBody);
+
+ return deserialize(jsonBody);
+ } else {
+ throw new RuntimeException(
+ "Could not get " + uri + ": " + res.statusCode() + "
to determine the Quarkus Platform version."
+ + " You may want to pass
--download=false to use the cached resource if available"
+ + " or pass and explicit
--quarkus-version if the current command supports it");
}
- } catch (Exception e) {
- // ignore - if the registry is not reachable within 2 seconds,
return null
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new RuntimeException("Interrupted when fetching from " +
quarkusPlatformUrl, e);
+ } catch (IOException e) {
+ throw new RuntimeException("Could not fetch from " +
quarkusPlatformUrl, e);
+ } catch (URISyntaxException e) {
+ throw new RuntimeException("Unvalid URI " + quarkusPlatformUrl, e);
Review Comment:
Solved in 164c2bd
##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java:
##########
@@ -372,27 +394,44 @@ private void createMavenPom(Path settings, Path pom,
Set<String> deps) throws Ex
Files.writeString(pom, context);
}
- private List<Map<String, Object>> buildQuarkusDependencyList(Set<String>
deps, CamelCatalog catalog) {
+ private List<Map<String, Object>> buildQuarkusDependencyList(Set<String>
deps, MavenGav quarkusCamelBom) {
List<MavenGav> gavs = new ArrayList<>();
- for (String dep : deps) {
- MavenGav gav = parseMavenGav(dep);
- String gid = gav.getGroupId();
- String aid = gav.getArtifactId();
- // transform to camel-quarkus extension GAV
- if ("org.apache.camel".equals(gid)) {
- String qaid = aid.replace("camel-", "camel-quarkus-");
- ArtifactModel<?> am =
catalog.modelFromMavenGAV("org.apache.camel.quarkus", qaid, null);
- if (am != null) {
- // use quarkus extension
- gav.setGroupId(am.getGroupId());
- gav.setArtifactId(am.getArtifactId());
- gav.setVersion(null); // uses BOM so version should not be
included
- } else {
- // there is no quarkus extension so use plain camel
- gav.setVersion(camelVersion);
+
+ Path file =
mavenResolver.downloader().resolveArtifact(quarkusCamelBom).getFile().toPath();
+ DocumentBuilderFactory dbf = XmlHelper.createDocumentBuilderFactory();
+
+ try (InputStream in = Files.newInputStream(file)) {
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ Document dom = db.parse(in);
+ XPath xPath = XPathFactory.newDefaultInstance().newXPath();
+ for (String dep : deps) {
+ MavenGav gav = parseMavenGav(dep);
+ String gid = gav.getGroupId();
+ String aid = gav.getArtifactId();
+ // transform to camel-quarkus extension GAV
+ if ("org.apache.camel".equals(gid)) {
+ String qaid = aid.replace("camel-", "camel-quarkus-");
+ if (nodeExists(file, dom, xPath,
"org.apache.camel.quarkus", qaid)) {
+ // use quarkus extension
+ gav.setGroupId("org.apache.camel.quarkus");
+ gav.setArtifactId(qaid);
+ gav.setVersion(null); // uses BOM so version should
not be included
+ } else if (nodeExists(file, dom, xPath,
"org.apache.camel", aid)) {
+ // The Camel artifact is managed in Quarkus Camel BOM
+ gav.setVersion(null);
+ } else {
+ // Use plain camel with hard-coded version
+ gav.setVersion(camelVersion);
+ }
}
+ gavs.add(gav);
}
- gavs.add(gav);
+ } catch (IOException e) {
+ throw new UncheckedIOException("Could not read " + file, e);
+ } catch (SAXException e) {
+ throw new RuntimeException("Could parse " + file, e);
Review Comment:
Solved in 164c2bd
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]