Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include relevant upstream catalogs even if their versions aren't recommended for new projects #19908

Merged
merged 1 commit into from
Sep 3, 2021
Merged
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
Include relevant upstream catalogs even if their versions aren't reco…
…mmended for new projects

Moved io.quarkus.maven.StreamCoords to io.quarkus.registry.catalog.PlatformStreamCoords
aloubyansky committed Sep 3, 2021
commit 9a15b82a7047d555f3bfdfb5530f046929539b79
Original file line number Diff line number Diff line change
@@ -2,15 +2,15 @@

import io.quarkus.cli.Version;
import io.quarkus.maven.ArtifactCoords;
import io.quarkus.maven.StreamCoords;
import io.quarkus.platform.tools.ToolsConstants;
import io.quarkus.registry.catalog.PlatformStreamCoords;
import picocli.CommandLine;
import picocli.CommandLine.Model.CommandSpec;

public class TargetQuarkusVersionGroup {
final static String FULL_EXAMPLE = ToolsConstants.DEFAULT_PLATFORM_BOM_GROUP_ID + ":"
+ ToolsConstants.DEFAULT_PLATFORM_BOM_ARTIFACT_ID + ":2.2.0.Final";
StreamCoords streamCoords = null;
PlatformStreamCoords streamCoords = null;
String validStream = null;

ArtifactCoords platformBom = null;
@@ -25,7 +25,7 @@ void setStream(String stream) {
stream = stream.trim();
if (!stream.isEmpty()) {
try {
streamCoords = StreamCoords.fromString(stream);
streamCoords = PlatformStreamCoords.fromString(stream);
validStream = stream;
} catch (IllegalArgumentException iex) {
throw new CommandLine.ParameterException(spec.commandLine(),
@@ -94,7 +94,7 @@ public boolean isStreamSpecified() {
return streamCoords != null;
}

public StreamCoords getStream() {
public PlatformStreamCoords getStream() {
return streamCoords;
}

Original file line number Diff line number Diff line change
@@ -5,8 +5,8 @@

import io.quarkus.cli.Version;
import io.quarkus.maven.ArtifactCoords;
import io.quarkus.maven.StreamCoords;
import io.quarkus.platform.tools.ToolsConstants;
import io.quarkus.registry.catalog.PlatformStreamCoords;

public class TargetQuarkusVersionGroupTest {
final static String clientVersion = Version.clientVersion();
@@ -64,7 +64,7 @@ void testPlatformUseDefaultGroupVersion() {
void testStreamUseDFullyQualified() {
qvg.setStream("stream-platform:stream-version");

StreamCoords coords = qvg.getStream();
PlatformStreamCoords coords = qvg.getStream();
Assertions.assertEquals("stream-platform", coords.getPlatformKey());
Assertions.assertEquals("stream-version", coords.getStreamId());
}
@@ -73,7 +73,7 @@ void testStreamUseDFullyQualified() {
void testStreamUseDefaultPlatformKey() {
qvg.setStream(":stream-version");

StreamCoords coords = qvg.getStream();
PlatformStreamCoords coords = qvg.getStream();
Assertions.assertNull(coords.getPlatformKey());
Assertions.assertEquals("stream-version", coords.getStreamId());
}
@@ -82,7 +82,7 @@ void testStreamUseDefaultPlatformKey() {
void testStreamUseDefaultStreamId() {
qvg.setStream("stream-platform:");

StreamCoords coords = qvg.getStream();
PlatformStreamCoords coords = qvg.getStream();
Assertions.assertEquals("stream-platform", coords.getPlatformKey());
Assertions.assertEquals("", coords.getStreamId());
}
Original file line number Diff line number Diff line change
@@ -120,6 +120,9 @@ private ExtensionCatalog deserializeExtensionCatalog(Path p) throws RegistryReso
public PlatformCatalog resolvePlatforms(String quarkusVersion) throws RegistryResolutionException {
final Path json = TestRegistryClientBuilder.getRegistryPlatformsCatalogPath(registryDir, quarkusVersion);
log.debug("%s resolvePlatforms %s", config.getId(), json);
if (!Files.exists(json)) {
return null;
}
try {
return JsonCatalogMapperHelper.deserialize(json, JsonPlatformCatalog.class);
} catch (IOException e) {
Original file line number Diff line number Diff line change
@@ -106,6 +106,7 @@ public static class TestRegistryBuilder {
private JsonRegistryQuarkusVersionsConfig quarkusVersions;
private boolean external;
private PlatformCatalog platformCatalog;
private JsonPlatformCatalog archivedPlatformCatalog;

private List<TestPlatformCatalogMemberBuilder> memberCatalogs;
private List<TestNonPlatformCatalogBuilder> nonPlatformCatalogs;
@@ -221,37 +222,72 @@ private void configure(Path registryDir) {
platformConfig
.setArtifact(new ArtifactCoords(registryGroupId, Constants.DEFAULT_REGISTRY_PLATFORMS_CATALOG_ARTIFACT_ID,
null, "json", Constants.DEFAULT_REGISTRY_ARTIFACT_VERSION));
if (platformCatalog == null) {
if (platformCatalog == null && archivedPlatformCatalog == null) {
platformConfig.setDisabled(true);
} else {
final Path platformsDir = getRegistryPlatformsDir(registryDir);
persistPlatformCatalog(platformCatalog, platformsDir);
final Map<String, JsonPlatformCatalog> platformsByQuarkusVersion = new HashMap<>();
for (Platform p : platformCatalog.getPlatforms()) {
for (PlatformStream s : p.getStreams()) {
for (PlatformRelease r : s.getReleases()) {
if (r.getQuarkusCoreVersion() == null) {
throw new IllegalStateException("Quarkus version has not be configured for platform release "
+ p.getPlatformKey() + ":" + s.getId() + ":" + r.getVersion());
}
final JsonPlatformCatalog c = platformsByQuarkusVersion.computeIfAbsent(r.getQuarkusCoreVersion(),
v -> new JsonPlatformCatalog());
JsonPlatform platform = (JsonPlatform) c.getPlatform(p.getPlatformKey());
if (platform == null) {
platform = new JsonPlatform();
platform.setPlatformKey(p.getPlatformKey());
c.addPlatform(platform);
if (platformCatalog != null) {
persistPlatformCatalog(platformCatalog, platformsDir);
for (Platform p : platformCatalog.getPlatforms()) {
for (PlatformStream s : p.getStreams()) {
for (PlatformRelease r : s.getReleases()) {
if (r.getQuarkusCoreVersion() == null) {
throw new IllegalStateException(
"Quarkus version has not be configured for platform release "
+ p.getPlatformKey() + ":" + s.getId() + ":" + r.getVersion());
}
final JsonPlatformCatalog c = platformsByQuarkusVersion.computeIfAbsent(
r.getQuarkusCoreVersion(),
v -> new JsonPlatformCatalog());
JsonPlatform platform = (JsonPlatform) c.getPlatform(p.getPlatformKey());
if (platform == null) {
platform = new JsonPlatform();
platform.setPlatformKey(p.getPlatformKey());
c.addPlatform(platform);
}
JsonPlatformStream stream = (JsonPlatformStream) platform.getStream(s.getId());
if (stream == null) {
stream = new JsonPlatformStream();
stream.setId(s.getId());
platform.addStream(stream);
}
stream.addRelease(r);
}
JsonPlatformStream stream = (JsonPlatformStream) platform.getStream(s.getId());
if (stream == null) {
stream = new JsonPlatformStream();
stream.setId(s.getId());
platform.addStream(stream);
}
}
}

if (archivedPlatformCatalog != null) {
for (Platform p : archivedPlatformCatalog.getPlatforms()) {
for (PlatformStream s : p.getStreams()) {
for (PlatformRelease r : s.getReleases()) {
if (r.getQuarkusCoreVersion() == null) {
throw new IllegalStateException(
"Quarkus version has not be configured for platform release "
+ p.getPlatformKey() + ":" + s.getId() + ":" + r.getVersion());
}
final JsonPlatformCatalog c = platformsByQuarkusVersion.computeIfAbsent(
r.getQuarkusCoreVersion(),
v -> new JsonPlatformCatalog());
JsonPlatform platform = (JsonPlatform) c.getPlatform(p.getPlatformKey());
if (platform == null) {
platform = new JsonPlatform();
platform.setPlatformKey(p.getPlatformKey());
c.addPlatform(platform);
}
JsonPlatformStream stream = (JsonPlatformStream) platform.getStream(s.getId());
if (stream == null) {
stream = new JsonPlatformStream();
stream.setId(s.getId());
platform.addStream(stream);
}
stream.addRelease(r);
}
stream.addRelease(r);
}
}
}

for (Map.Entry<String, JsonPlatformCatalog> entry : platformsByQuarkusVersion.entrySet()) {
persistPlatformCatalog(entry.getValue(), platformsDir.resolve(entry.getKey()));
}
@@ -339,6 +375,33 @@ public TestPlatformCatalogReleaseBuilder newRelease(String version) {
return new TestPlatformCatalogReleaseBuilder(this, release);
}

public TestPlatformCatalogReleaseBuilder newArchivedRelease(String version) {
final JsonPlatformRelease release = new JsonPlatformRelease();
release.setVersion(JsonPlatformReleaseVersion.fromString(version));

if (platform.registry.archivedPlatformCatalog == null) {
platform.registry.archivedPlatformCatalog = new JsonPlatformCatalog();
}

JsonPlatform archivedPlatform = (JsonPlatform) platform.registry.archivedPlatformCatalog
.getPlatform(platform.platform.getPlatformKey());
if (archivedPlatform == null) {
archivedPlatform = new JsonPlatform();
archivedPlatform.setPlatformKey(platform.platform.getPlatformKey());
platform.registry.archivedPlatformCatalog.addPlatform(archivedPlatform);
}

JsonPlatformStream archivedStream = (JsonPlatformStream) archivedPlatform.getStream(stream.getId());
if (archivedStream == null) {
archivedStream = new JsonPlatformStream();
archivedStream.setId(stream.getId());
archivedPlatform.addStream(archivedStream);
}

archivedStream.addRelease(release);
return new TestPlatformCatalogReleaseBuilder(this, release);
}

public TestPlatformCatalogPlatformBuilder platform() {
return platform;
}
Original file line number Diff line number Diff line change
@@ -13,6 +13,8 @@
import io.quarkus.devtools.project.QuarkusProjectHelper;
import io.quarkus.devtools.testing.registry.client.TestRegistryClientBuilder;
import io.quarkus.maven.ArtifactCoords;
import io.quarkus.registry.RegistryResolutionException;
import io.quarkus.registry.catalog.PlatformStreamCoords;
import io.quarkus.registry.config.RegistriesConfigLocator;
import java.io.IOException;
import java.nio.file.Files;
@@ -89,7 +91,7 @@ protected QuarkusCommandOutcome addExtensions(Path projectDir, List<String> exte

protected QuarkusCommandOutcome createProject(Path projectDir, List<String> extensions)
throws Exception {
return createProject(projectDir, null, extensions);
return createProject(projectDir, (String) null, extensions);
}

protected QuarkusCommandOutcome createProject(Path projectDir, String quarkusVersion, List<String> extensions)
@@ -103,6 +105,17 @@ protected QuarkusCommandOutcome createProject(Path projectDir, String quarkusVer
.execute();
}

protected QuarkusCommandOutcome createProject(Path projectDir, PlatformStreamCoords stream, List<String> extensions)
throws Exception {
return new CreateProject(
getQuarkusProject(projectDir, stream))
.groupId("org.acme")
.artifactId("acme-app")
.version("0.0.1-SNAPSHOT")
.extensions(new HashSet<>(extensions))
.execute();
}

protected List<ArtifactCoords> toPlatformExtensionCoords(String... artifactIds) {
return toPlatformExtensionCoords(Arrays.asList(artifactIds));
}
@@ -171,6 +184,12 @@ protected QuarkusProject getQuarkusProject(Path projectDir, String quarkusVersio
return QuarkusProjectHelper.getProject(projectDir, BuildTool.MAVEN, quarkusVersion);
}

protected QuarkusProject getQuarkusProject(Path projectDir, PlatformStreamCoords stream)
throws RegistryResolutionException {
return QuarkusProjectHelper.getProject(projectDir,
QuarkusProjectHelper.getCatalogResolver().resolveExtensionCatalog(stream), BuildTool.MAVEN);
}

static Path newProjectDir(String name) {
Path projectDir = getProjectDir(name);
if (Files.exists(projectDir)) {
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package io.quarkus.devtools.project.create;

import io.quarkus.devtools.testing.registry.client.TestRegistryClientBuilder;
import io.quarkus.maven.ArtifactCoords;
import io.quarkus.registry.catalog.PlatformStreamCoords;
import java.nio.file.Path;
import java.util.Arrays;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

public class QuarkusPlatformReferencingArchivedUpstreamVersionTest extends MultiplePlatformBomsTestBase {

private static final String DOWNSTREAM_PLATFORM_KEY = "io.downstream.platform";
private static final String UPSTREAM_PLATFORM_KEY = "io.upstream.platform";

@BeforeAll
public static void setup() throws Exception {
TestRegistryClientBuilder.newInstance()
//.debug()
.baseDir(configDir())
// registry
.newRegistry("downstream.registry.test")
.recognizedQuarkusVersions("*-downstream")
// platform key
.newPlatform(DOWNSTREAM_PLATFORM_KEY)
// 2.0 STREAM
.newStream("2.0")
// 2.0.4 release
.newRelease("2.0.4-downstream")
.quarkusVersion("2.2.2-downstream")
.upstreamQuarkusVersion("2.2.2")
// default bom including quarkus-core + essential metadata
.addCoreMember()
// foo platform member
.newMember("acme-foo-bom").addExtension("io.acme", "ext-a", "2.0.4-downstream").release().stream().platform()
.newStream("1.0")
// 1.0.4 release
.newRelease("1.0.4-downstream")
.quarkusVersion("1.1.1-downstream")
.upstreamQuarkusVersion("1.1.1")
// default bom including quarkus-core + essential metadata
.addCoreMember()
// foo platform member
.newMember("acme-foo-bom").addExtension("io.acme", "ext-a", "1.0.4-downstream").release()
.newMember("acme-e-bom").addExtension("io.acme", "ext-e", "1.0.4-downstream").release()
.stream().platform().registry()
.newNonPlatformCatalog("1.1.1-downstream").addExtension("io.acme", "ext-d", "4.0-downstream").registry()
.clientBuilder()
.newRegistry("upstream.registry.test")
// platform key
.newPlatform(UPSTREAM_PLATFORM_KEY)
// 2.0 STREAM
.newStream("2.0")
// 2.0.5 release
.newRelease("2.0.5")
.quarkusVersion("2.2.5")
// default bom including quarkus-core + essential metadata
.addCoreMember()
.newMember("acme-foo-bom").addExtension("io.acme", "ext-a", "2.0.5").release()
.newMember("acme-e-bom").addExtension("io.acme", "ext-e", "2.0.5").release()
.newMember("acme-bar-bom").addExtension("io.acme", "ext-b", "2.0.5").release().stream()
// 2.0.4 release
.newArchivedRelease("2.0.4")
.quarkusVersion("2.2.2")
// default bom including quarkus-core + essential metadata
.addCoreMember()
.newMember("acme-foo-bom").addExtension("io.acme", "ext-a", "2.0.4").release()
.newMember("acme-e-bom").addExtension("io.acme", "ext-e", "2.0.4").release()
.newMember("acme-bar-bom").addExtension("io.acme", "ext-b", "2.0.4").release().stream().platform()
// 1.0 STREAM
.newStream("1.0")
.newRelease("1.0.5")
.quarkusVersion("1.1.5")
// default bom including quarkus-core + essential metadata
.addCoreMember()
.newMember("acme-foo-bom").addExtension("io.acme", "ext-a", "1.0.5").addExtension("io.acme", "ext-e", "1.0.5")
.release()
.newMember("acme-bar-bom").addExtension("io.acme", "ext-b", "1.0.5").release()
.stream()
.newArchivedRelease("1.0.4")
.quarkusVersion("1.1.1")
// default bom including quarkus-core + essential metadata
.addCoreMember()
.newMember("acme-foo-bom").addExtension("io.acme", "ext-a", "1.0.4").addExtension("io.acme", "ext-e", "1.0.4")
.release()
.newMember("acme-bar-bom").addExtension("io.acme", "ext-b", "1.0.4").release()
.stream().platform().registry()
.newNonPlatformCatalog("2.2.2").addExtension("io.acme", "ext-c", "5.1").addExtension("io.acme", "ext-d", "6.0")
.registry()
.clientBuilder()
.build();

enableRegistryClient();
}

protected String getMainPlatformKey() {
return DOWNSTREAM_PLATFORM_KEY;
}

@Test
public void addExtensionsFromAlreadyImportedPlatform() throws Exception {
final Path projectDir = newProjectDir("downstream-upstream-platform");
createProject(projectDir, Arrays.asList("ext-a"));

assertModel(projectDir,
toPlatformBomCoords("acme-foo-bom"),
Arrays.asList(new ArtifactCoords("io.acme", "ext-a", null)),
"2.0.4-downstream");

addExtensions(projectDir, Arrays.asList("ext-b", "ext-c", "ext-d", "ext-e"));
assertModel(projectDir,
Arrays.asList(mainPlatformBom(), platformMemberBomCoords("acme-foo-bom"),
new ArtifactCoords(UPSTREAM_PLATFORM_KEY, "acme-bar-bom", "pom", "2.0.4"),
new ArtifactCoords(UPSTREAM_PLATFORM_KEY, "acme-e-bom", "pom", "2.0.4")),
Arrays.asList(new ArtifactCoords("io.acme", "ext-a", null),
new ArtifactCoords("io.acme", "ext-b", null),
new ArtifactCoords("io.acme", "ext-e", null),
new ArtifactCoords("io.acme", "ext-c", "jar", "5.1"),
new ArtifactCoords("io.acme", "ext-d", "jar", "6.0")),
"2.0.4-downstream");
}

@Test
public void createWithExtensionsFromDifferentPlatforms() throws Exception {
final Path projectDir = newProjectDir("create-downstream-upstream-platform");
createProject(projectDir, Arrays.asList("ext-a", "ext-b"));

assertModel(projectDir,
Arrays.asList(mainPlatformBom(), platformMemberBomCoords("acme-foo-bom"),
new ArtifactCoords(UPSTREAM_PLATFORM_KEY, "acme-bar-bom", "pom", "2.0.4")),
Arrays.asList(new ArtifactCoords("io.acme", "ext-a", null), new ArtifactCoords("io.acme", "ext-b", null)),
"2.0.4-downstream");
}

@Test
public void createPreferringOlderStreamToNewerStreamCoveringLessExtensions() throws Exception {
final Path projectDir = newProjectDir("create-downstream-upstream-platform");
createProject(projectDir, Arrays.asList("ext-a", "ext-b", "ext-e"));

assertModel(projectDir,
Arrays.asList(mainPlatformBom(), platformMemberBomCoords("acme-foo-bom"), platformMemberBomCoords("acme-e-bom"),
new ArtifactCoords(UPSTREAM_PLATFORM_KEY, "acme-bar-bom", "pom", "1.0.4")),
Arrays.asList(new ArtifactCoords("io.acme", "ext-a", null), new ArtifactCoords("io.acme", "ext-b", null),
new ArtifactCoords("io.acme", "ext-e", null)),
"1.0.4-downstream");
}

@Test
public void createUsingStream2_0() throws Exception {
final Path projectDir = newProjectDir("created-using-downstream-stream");
createProject(projectDir, new PlatformStreamCoords(DOWNSTREAM_PLATFORM_KEY, "2.0"),
Arrays.asList("ext-a", "ext-b", "ext-e"));

assertModel(projectDir,
Arrays.asList(mainPlatformBom(), platformMemberBomCoords("acme-foo-bom"),
new ArtifactCoords(UPSTREAM_PLATFORM_KEY, "acme-e-bom", "pom", "2.0.4"),
new ArtifactCoords(UPSTREAM_PLATFORM_KEY, "acme-bar-bom", "pom", "2.0.4")),
Arrays.asList(new ArtifactCoords("io.acme", "ext-a", null), new ArtifactCoords("io.acme", "ext-b", null),
new ArtifactCoords("io.acme", "ext-e", null)),
"2.0.4-downstream");
}
}
Original file line number Diff line number Diff line change
@@ -4,12 +4,12 @@
import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver;
import io.quarkus.devtools.messagewriter.MessageWriter;
import io.quarkus.maven.ArtifactCoords;
import io.quarkus.maven.StreamCoords;
import io.quarkus.registry.catalog.ExtensionCatalog;
import io.quarkus.registry.catalog.Platform;
import io.quarkus.registry.catalog.PlatformCatalog;
import io.quarkus.registry.catalog.PlatformRelease;
import io.quarkus.registry.catalog.PlatformStream;
import io.quarkus.registry.catalog.PlatformStreamCoords;
import io.quarkus.registry.catalog.json.JsonCatalogMerger;
import io.quarkus.registry.catalog.json.JsonExtensionCatalog;
import io.quarkus.registry.catalog.json.JsonPlatform;
@@ -291,6 +291,15 @@ public PlatformCatalog resolvePlatformCatalog(String quarkusVersion) throws Regi
return result;
}

private void collectPlatforms(PlatformCatalog catalog, List<Platform> collectedPlatforms,
Set<String> collectedPlatformKeys) {
for (Platform p : catalog.getPlatforms()) {
if (collectedPlatformKeys.add(p.getPlatformKey())) {
collectedPlatforms.add(p);
}
}
}

public PlatformCatalog resolvePlatformCatalogFromRegistry(String registryId) throws RegistryResolutionException {
return registries.get(getRegistryIndex(registryId)).resolvePlatformCatalog();
}
@@ -301,15 +310,6 @@ public PlatformCatalog resolvePlatformCatalogFromRegistry(String registryId, Str
: registries.get(getRegistryIndex(registryId)).resolvePlatformCatalog(quarkusVersion);
}

private void collectPlatforms(PlatformCatalog catalog, List<Platform> collectedPlatforms,
Set<String> collectedPlatformKeys) {
for (Platform p : catalog.getPlatforms()) {
if (collectedPlatformKeys.add(p.getPlatformKey())) {
collectedPlatforms.add(p);
}
}
}

private class ExtensionCatalogBuilder {
private final List<ExtensionCatalog> catalogs = new ArrayList<>();
final Map<String, List<RegistryExtensionResolver>> registriesByQuarkusCore = new HashMap<>();
@@ -320,6 +320,12 @@ void addCatalog(ExtensionCatalog c) {
catalogs.add(c);
}

void addUpstreamQuarkusVersion(String quarkusVersion) {
if (!upstreamQuarkusVersions.contains(quarkusVersion)) {
upstreamQuarkusVersions.add(quarkusVersion);
}
}

List<RegistryExtensionResolver> getRegistriesForQuarkusCore(String quarkusVersion) {
return registriesByQuarkusCore.computeIfAbsent(quarkusVersion, v -> getRegistriesForQuarkusVersion(v));
}
@@ -364,41 +370,71 @@ public ExtensionCatalog resolveExtensionCatalog() throws RegistryResolutionExcep
final ExtensionCatalogBuilder catalogBuilder = new ExtensionCatalogBuilder();

for (int registryIndex = 0; registryIndex < registries.size(); ++registryIndex) {
RegistryExtensionResolver registry = registries.get(registryIndex);
final PlatformCatalog pc = registry.resolvePlatformCatalog();
collectPlatformExtensions(catalogBuilder, registryIndex);
}

return catalogBuilder.build();
}

private void collectPlatformExtensions(final ExtensionCatalogBuilder catalogBuilder, int registryIndex)
throws RegistryResolutionException {
final RegistryExtensionResolver registry = registries.get(registryIndex);

final List<PlatformCatalog> downstreamPreferences = new ArrayList<>(catalogBuilder.upstreamQuarkusVersions.size());
for (String quarkusVersion : catalogBuilder.upstreamQuarkusVersions) {
if (!registry.isAcceptsQuarkusVersionQueries(quarkusVersion)) {
continue;
}
final PlatformCatalog pc = registry.resolvePlatformCatalog(quarkusVersion);
if (pc == null) {
continue;
}
int platformIndex = 0;
for (Platform platform : pc.getPlatforms()) {
platformIndex++;
for (PlatformStream stream : platform.getStreams()) {
int releaseIndex = 0;
for (PlatformRelease release : stream.getReleases()) {
releaseIndex++;
final int compatiblityCode = catalogBuilder
.getCompatibilityCode(release.getQuarkusCoreVersion(),
release.getUpstreamQuarkusCoreVersion());

int memberIndex = 0;
for (ArtifactCoords bom : release.getMemberBoms()) {
memberIndex++;
final ExtensionCatalog ec = registry.resolvePlatformExtensions(bom);
if (ec != null) {
final OriginPreference originPreference = new OriginPreference(registryIndex, platformIndex,
releaseIndex, memberIndex, compatiblityCode);
addOriginPreference(ec, originPreference);
catalogBuilder.addCatalog(ec);
} else {
log.warn("Failed to resolve extension catalog for %s from registry %s", bom, registry.getId());
}
downstreamPreferences.add(pc);
}

PlatformCatalog pc = registry.resolvePlatformCatalog();
if (pc == null && downstreamPreferences.isEmpty()) {
return;
}
if (!downstreamPreferences.isEmpty()) {
downstreamPreferences.add(pc);
pc = JsonCatalogMerger.mergePlatformCatalogs(downstreamPreferences);
}

int platformIndex = 0;
for (Platform platform : pc.getPlatforms()) {
platformIndex++;
for (PlatformStream stream : platform.getStreams()) {
int releaseIndex = 0;
for (PlatformRelease release : stream.getReleases()) {
releaseIndex++;
final String quarkusVersion = release.getQuarkusCoreVersion();
final int compatiblityCode = catalogBuilder.getCompatibilityCode(quarkusVersion,
release.getUpstreamQuarkusCoreVersion());

if (!registry.isExclusiveProviderOf(quarkusVersion)) {
catalogBuilder.addUpstreamQuarkusVersion(quarkusVersion);
}
if (release.getUpstreamQuarkusCoreVersion() != null) {
catalogBuilder.addUpstreamQuarkusVersion(release.getUpstreamQuarkusCoreVersion());
}

int memberIndex = 0;
for (ArtifactCoords bom : release.getMemberBoms()) {
memberIndex++;
final ExtensionCatalog ec = registry.resolvePlatformExtensions(bom);
if (ec != null) {
final OriginPreference originPreference = new OriginPreference(registryIndex, platformIndex,
releaseIndex, memberIndex, compatiblityCode);
addOriginPreference(ec, originPreference);
catalogBuilder.addCatalog(ec);
} else {
log.warn("Failed to resolve extension catalog for %s from registry %s", bom, registry.getId());
}
}
}
}
}

return catalogBuilder.build();
}

private void addOriginPreference(final ExtensionCatalog ec, OriginPreference originPreference) {
@@ -426,25 +462,22 @@ public ExtensionCatalog resolveExtensionCatalog(String quarkusCoreVersion) throw
private ExtensionCatalog resolveExtensionCatalog(String quarkusCoreVersion,
final ExtensionCatalogBuilder catalogBuilder, Set<String> preferredPlatforms)
throws RegistryResolutionException {
collectPlatforms(quarkusCoreVersion, catalogBuilder, preferredPlatforms);
collectPlatformExtensions(quarkusCoreVersion, catalogBuilder, preferredPlatforms);
int i = 0;
while (i < catalogBuilder.upstreamQuarkusVersions.size()) {
collectPlatforms(catalogBuilder.upstreamQuarkusVersions.get(i++), catalogBuilder, preferredPlatforms);
collectPlatformExtensions(catalogBuilder.upstreamQuarkusVersions.get(i++), catalogBuilder, preferredPlatforms);
}
return catalogBuilder.build();
}

public ExtensionCatalog resolveExtensionCatalog(StreamCoords streamCoords) throws RegistryResolutionException {
public ExtensionCatalog resolveExtensionCatalog(PlatformStreamCoords streamCoords) throws RegistryResolutionException {

ensureRegistriesConfigured();

final ExtensionCatalogBuilder catalogBuilder = new ExtensionCatalogBuilder();

final String platformKey = streamCoords.getPlatformKey();
final String streamId = streamCoords.getStreamId();

PlatformStream stream = null;
RegistryExtensionResolver registry = null;
int registryIndex = 0;
while (registryIndex < registries.size()) {
final RegistryExtensionResolver qer = registries.get(registryIndex++);
@@ -456,7 +489,6 @@ public ExtensionCatalog resolveExtensionCatalog(StreamCoords streamCoords) throw
for (Platform p : platforms.getPlatforms()) {
stream = p.getStream(streamId);
if (stream != null) {
registry = qer;
break;
}
}
@@ -466,7 +498,6 @@ public ExtensionCatalog resolveExtensionCatalog(StreamCoords streamCoords) throw
continue;
}
stream = platform.getStream(streamId);
registry = qer;
}
break;
}
@@ -510,24 +541,12 @@ public ExtensionCatalog resolveExtensionCatalog(StreamCoords streamCoords) throw
throw new RegistryResolutionException(buf.toString());
}

int releaseIndex = 0;
final List<ExtensionCatalog> catalogs = new ArrayList<>();
for (PlatformRelease release : stream.getReleases()) {
final int compatiblityCode = catalogBuilder
.getCompatibilityCode(release.getQuarkusCoreVersion(),
release.getUpstreamQuarkusCoreVersion());
++releaseIndex;
int memberIndex = 0;
for (ArtifactCoords bom : release.getMemberBoms()) {
final ExtensionCatalog ec = registry.resolvePlatformExtensions(bom);
final OriginPreference originPreference = new OriginPreference(registryIndex, 1,
releaseIndex, ++memberIndex, compatiblityCode);
addOriginPreference(ec, originPreference);

catalogBuilder.addCatalog(ec);
}
catalogs.add(resolveExtensionCatalog(release.getMemberBoms()));
}

return catalogBuilder.build();
return JsonCatalogMerger.merge(catalogs);
}

@SuppressWarnings("unchecked")
@@ -623,7 +642,7 @@ public ExtensionCatalog resolveExtensionCatalog(Collection<ArtifactCoords> prefe
release.setMemberBoms(coords);
}

collectPlatforms(quarkusVersion, catalogBuilder, registry, platformIndex,
collectPlatformExtensions(quarkusVersion, catalogBuilder, registry, platformIndex,
p);
continue;
}
@@ -688,8 +707,8 @@ private int getRegistryIndex(String registryId) {
throw new IllegalStateException(buf.toString());
}

private void collectPlatforms(String quarkusCoreVersion, ExtensionCatalogBuilder catalogBuilder,
Set<String> preferredPlatforms)
private void collectPlatformExtensions(String quarkusCoreVersion, ExtensionCatalogBuilder catalogBuilder,
Set<String> processedPlatforms)
throws RegistryResolutionException {
final List<RegistryExtensionResolver> quarkusVersionRegistries = catalogBuilder
.getRegistriesForQuarkusCore(quarkusCoreVersion);
@@ -703,18 +722,18 @@ private void collectPlatforms(String quarkusCoreVersion, ExtensionCatalogBuilder
if (platforms.isEmpty()) {
continue;
}
int platformIndex = preferredPlatforms.size();
int platformIndex = processedPlatforms.size();
for (Platform p : platforms) {
if (preferredPlatforms.contains(p.getPlatformKey())) {
if (processedPlatforms.contains(p.getPlatformKey())) {
continue;
}
++platformIndex;
collectPlatforms(quarkusCoreVersion, catalogBuilder, registry, platformIndex, p);
collectPlatformExtensions(quarkusCoreVersion, catalogBuilder, registry, platformIndex, p);
}
}
}

private void collectPlatforms(String quarkusCoreVersion, ExtensionCatalogBuilder catalogBuilder,
private void collectPlatformExtensions(String quarkusCoreVersion, ExtensionCatalogBuilder catalogBuilder,
RegistryExtensionResolver registry, int platformIndex,
Platform p) throws RegistryResolutionException {
for (PlatformStream s : p.getStreams()) {
@@ -738,9 +757,8 @@ private void collectPlatforms(String quarkusCoreVersion, ExtensionCatalogBuilder
}

final String upstreamQuarkusVersion = r.getUpstreamQuarkusCoreVersion();
if (upstreamQuarkusVersion != null
&& !catalogBuilder.upstreamQuarkusVersions.contains(upstreamQuarkusVersion)) {
catalogBuilder.upstreamQuarkusVersions.add(upstreamQuarkusVersion);
if (upstreamQuarkusVersion != null) {
catalogBuilder.addUpstreamQuarkusVersion(upstreamQuarkusVersion);
}
}
}
Original file line number Diff line number Diff line change
@@ -56,6 +56,14 @@ int checkQuarkusVersion(String quarkusVersion) {
: VERSION_RECOGNIZED;
}

boolean isExclusiveProviderOf(String quarkusVersion) {
return checkQuarkusVersion(quarkusVersion) == VERSION_EXCLUSIVE_PROVIDER;
}

boolean isAcceptsQuarkusVersionQueries(String quarkusVersion) {
return checkQuarkusVersion(quarkusVersion) >= 0;
}

int checkPlatform(ArtifactCoords platform) {
// TODO this should be allowed to check the full coordinates
return checkQuarkusVersion(platform.getVersion());
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package io.quarkus.maven;
package io.quarkus.registry.catalog;

public class StreamCoords {
public class PlatformStreamCoords {
final String platformKey;
final String streamId;

public static StreamCoords fromString(String stream) {
public static PlatformStreamCoords fromString(String stream) {
final int colon = stream.indexOf(':');
String platformKey = colon <= 0 ? null : stream.substring(0, colon);
String streamId = colon < 0 ? stream : stream.substring(colon + 1);
return new StreamCoords(platformKey, streamId);
return new PlatformStreamCoords(platformKey, streamId);
}

public StreamCoords(String platformKey, String streamId) {
public PlatformStreamCoords(String platformKey, String streamId) {
this.platformKey = platformKey;
this.streamId = streamId;
}
Original file line number Diff line number Diff line change
@@ -5,6 +5,10 @@
import io.quarkus.registry.catalog.Extension;
import io.quarkus.registry.catalog.ExtensionCatalog;
import io.quarkus.registry.catalog.ExtensionOrigin;
import io.quarkus.registry.catalog.Platform;
import io.quarkus.registry.catalog.PlatformCatalog;
import io.quarkus.registry.catalog.PlatformRelease;
import io.quarkus.registry.catalog.PlatformStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -72,6 +76,48 @@ public static ExtensionCatalog merge(List<ExtensionCatalog> catalogs) {
return combined;
}

public static PlatformCatalog mergePlatformCatalogs(List<PlatformCatalog> catalogs) {
if (catalogs.isEmpty()) {
throw new IllegalArgumentException("No catalogs provided");
}
if (catalogs.size() == 1) {
return catalogs.get(0);
}
final JsonPlatformCatalog merged = new JsonPlatformCatalog();
final Map<String, JsonPlatform> platformMap = new HashMap<>();
for (PlatformCatalog c : catalogs) {
for (Platform p : c.getPlatforms()) {
final JsonPlatform mergedPlatform = platformMap.computeIfAbsent(p.getPlatformKey(), k -> {
final JsonPlatform pl = new JsonPlatform();
pl.setPlatformKey(p.getPlatformKey());
merged.addPlatform(pl);
return pl;
});
for (PlatformStream s : p.getStreams()) {
JsonPlatformStream mergedStream = (JsonPlatformStream) mergedPlatform.getStream(s.getId());
if (mergedStream == null) {
mergedStream = new JsonPlatformStream();
mergedStream.setId(s.getId());
mergedPlatform.addStream(mergedStream);
}
for (PlatformRelease r : s.getReleases()) {
final PlatformRelease release = mergedStream.getRelease(r.getVersion());
if (release == null) {
mergedStream.addRelease(r);
}
}
final Map<String, Object> mergedStreamMetadata = mergedStream.getMetadata();
s.getMetadata().entrySet()
.forEach(entry -> mergedStreamMetadata.putIfAbsent(entry.getKey(), entry.getValue()));
}
p.getMetadata().entrySet()
.forEach(entry -> mergedPlatform.getMetadata().putIfAbsent(entry.getKey(), entry.getValue()));
}
c.getMetadata().entrySet().forEach(entry -> merged.getMetadata().putIfAbsent(entry.getKey(), entry.getValue()));
}
return merged;
}

private static List<ExtensionCatalog> detectRoots(List<ExtensionCatalog> catalogs) {
final Set<String> allDerivedFrom = new HashSet<>(catalogs.size());
for (ExtensionCatalog catalog : catalogs) {
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package io.quarkus.registry.catalog.json;

import static org.assertj.core.api.Assertions.assertThat;

import io.quarkus.maven.ArtifactCoords;
import io.quarkus.registry.catalog.Platform;
import io.quarkus.registry.catalog.PlatformCatalog;
import io.quarkus.registry.catalog.PlatformRelease;
import io.quarkus.registry.catalog.PlatformStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.junit.jupiter.api.Test;

public class JsonCatalogMergerTest {

@Test
void testMergePlatformCatalogs() throws Exception {

final List<PlatformCatalog> catalogs = new ArrayList<>();

JsonPlatformCatalog c = new JsonPlatformCatalog();
catalogs.add(c);
JsonPlatform p = new JsonPlatform();
c.addPlatform(p);
p.setPlatformKey("platform");
JsonPlatformStream s = new JsonPlatformStream();
s.setId("2.0");
p.addStream(s);
JsonPlatformRelease r = new JsonPlatformRelease();
r.setQuarkusCoreVersion("2.0.0");
r.setVersion(JsonPlatformReleaseVersion.fromString("2.2.2"));
r.setMemberBoms(Collections.singletonList(ArtifactCoords.fromString("org.acme:acme-quarkus-bom::pom:2.2.2")));
s.addRelease(r);

s = new JsonPlatformStream();
s.setId("1.0");
p.addStream(s);
r = new JsonPlatformRelease();
r.setQuarkusCoreVersion("1.0.1");
r.setVersion(JsonPlatformReleaseVersion.fromString("1.1.2"));
r.setMemberBoms(Collections.singletonList(ArtifactCoords.fromString("org.acme:acme-quarkus-bom::pom:1.1.2")));
s.addRelease(r);

c = new JsonPlatformCatalog();
catalogs.add(c);
p = new JsonPlatform();
c.addPlatform(p);
p.setPlatformKey("platform");
s = new JsonPlatformStream();
s.setId("2.0");
p.addStream(s);
r = new JsonPlatformRelease();
r.setQuarkusCoreVersion("2.0.1");
r.setVersion(JsonPlatformReleaseVersion.fromString("2.2.3"));
r.setMemberBoms(Collections.singletonList(ArtifactCoords.fromString("org.acme:acme-quarkus-bom::pom:2.2.3")));
s.addRelease(r);

s = new JsonPlatformStream();
s.setId("1.0");
p.addStream(s);
r = new JsonPlatformRelease();
r.setQuarkusCoreVersion("1.0.0");
r.setVersion(JsonPlatformReleaseVersion.fromString("1.1.1"));
r.setMemberBoms(Collections.singletonList(ArtifactCoords.fromString("org.acme:acme-quarkus-bom::pom:1.1.1")));
s.addRelease(r);

final PlatformCatalog merged = JsonCatalogMerger.mergePlatformCatalogs(catalogs);
Collection<Platform> platforms = merged.getPlatforms();
assertThat(platforms.size()).isEqualTo(1);
Platform platform = platforms.iterator().next();
assertThat(platform.getPlatformKey()).isEqualTo("platform");
assertThat(platform.getStreams().size()).isEqualTo(2);
Iterator<PlatformStream> streams = platform.getStreams().iterator();
PlatformStream stream = streams.next();
assertThat(stream.getId()).isEqualTo("2.0");
assertThat(stream.getReleases().size()).isEqualTo(2);
Iterator<PlatformRelease> releases = stream.getReleases().iterator();
PlatformRelease release = releases.next();
assertThat(release.getVersion()).isEqualTo(JsonPlatformReleaseVersion.fromString("2.2.2"));
assertThat(release.getQuarkusCoreVersion()).isEqualTo("2.0.0");
release = releases.next();
assertThat(release.getVersion()).isEqualTo(JsonPlatformReleaseVersion.fromString("2.2.3"));
assertThat(release.getQuarkusCoreVersion()).isEqualTo("2.0.1");

stream = streams.next();
assertThat(stream.getId()).isEqualTo("1.0");
assertThat(stream.getReleases().size()).isEqualTo(2);
releases = stream.getReleases().iterator();
release = releases.next();
assertThat(release.getVersion()).isEqualTo(JsonPlatformReleaseVersion.fromString("1.1.2"));
assertThat(release.getQuarkusCoreVersion()).isEqualTo("1.0.1");
release = releases.next();
assertThat(release.getVersion()).isEqualTo(JsonPlatformReleaseVersion.fromString("1.1.1"));
assertThat(release.getQuarkusCoreVersion()).isEqualTo("1.0.0");
}
}