diff --git a/build-parent/pom.xml b/build-parent/pom.xml index 36d719186bfee1..e30becd151ecce 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -154,30 +154,29 @@ </dependency> <!-- Dev tools --> - <dependency> <groupId>io.quarkus</groupId> - <artifactId>quarkus-devmode-test-utils</artifactId> + <artifactId>quarkus-devtools-registry-client</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>io.quarkus</groupId> - <artifactId>quarkus-devtools-utilities</artifactId> + <artifactId>quarkus-test-devtools</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>io.quarkus</groupId> - <artifactId>quarkus-devtools-common</artifactId> + <artifactId>quarkus-devmode-test-utils</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>io.quarkus</groupId> - <artifactId>quarkus-platform-descriptor-api</artifactId> + <artifactId>quarkus-devtools-utilities</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>io.quarkus</groupId> - <artifactId>quarkus-platform-descriptor-resolver-json</artifactId> + <artifactId>quarkus-devtools-common</artifactId> <version>${project.version}</version> </dependency> <dependency> @@ -318,6 +317,7 @@ <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager> <maven.home>${maven.home}</maven.home> <maven.repo>${settings.localRepository}</maven.repo> + <project.version>${project.version}</project.version> <!-- some dev tools tests need this --> </systemPropertyVariables> <argLine>${jacoco.agent.argLine} -Xmx1500m</argLine> <!-- limit the amount of memory surefire can use, 1500m should be plenty--> <!-- https://lists.apache.org/thread.html/r9030808273c82ac6d7b9602d34d446c7d8c4e8aa02c41bca164df1c5%40%3Cdev.maven.apache.org%3E --> @@ -332,6 +332,7 @@ <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager> <maven.home>${maven.home}</maven.home> <maven.repo>${settings.localRepository}</maven.repo> + <project.version>${project.version}</project.version> <!-- some dev tools tests need this --> </systemPropertyVariables> <!-- https://lists.apache.org/thread.html/r9030808273c82ac6d7b9602d34d446c7d8c4e8aa02c41bca164df1c5%40%3Cdev.maven.apache.org%3E --> <trimStackTrace>false</trimStackTrace> diff --git a/devtools/bom-descriptor-json/pom.xml b/devtools/bom-descriptor-json/pom.xml index ae87367dc470df..2979d4654ae85e 100644 --- a/devtools/bom-descriptor-json/pom.xml +++ b/devtools/bom-descriptor-json/pom.xml @@ -19,6 +19,27 @@ <build> <plugins> + <plugin> + <artifactId>maven-resources-plugin</artifactId> + <executions> + <execution> + <id>copy-resources</id> + <phase>validate</phase> + <goals> + <goal>copy-resources</goal> + </goals> + <configuration> + <outputDirectory>${basedir}/target/resources</outputDirectory> + <resources> + <resource> + <directory>${basedir}/src/main/resources</directory> + <filtering>true</filtering> + </resource> + </resources> + </configuration> + </execution> + </executions> + </plugin> <plugin> <groupId>io.quarkus</groupId> <artifactId>quarkus-platform-descriptor-json-plugin</artifactId> @@ -27,7 +48,8 @@ <execution> <phase>${pluginPhase}</phase> <goals> - <goal>generate-extensions-json</goal> + <!-- goal>generate-extensions-json</goal --> + <goal>generate-platform-descriptor-json</goal> </goals> <configuration> <ignoredGroupIds> @@ -35,6 +57,7 @@ </ignoredGroupIds> <bomArtifactId>quarkus-bom</bomArtifactId> <resolveDependencyManagement>true</resolveDependencyManagement> + <overridesFile>${basedir}/target/resources/catalog-overrides.json</overridesFile> </configuration> </execution> </executions> @@ -2460,4 +2483,4 @@ </profile> </profiles> -</project> +</project> \ No newline at end of file diff --git a/devtools/bom-descriptor-json/src/main/resources/catalog-overrides.json b/devtools/bom-descriptor-json/src/main/resources/catalog-overrides.json new file mode 100644 index 00000000000000..3ac9f49cc7f65b --- /dev/null +++ b/devtools/bom-descriptor-json/src/main/resources/catalog-overrides.json @@ -0,0 +1,28 @@ +{ + "metadata":{ + "project": { + "properties": { + "doc-root": "https://quarkus.io", + "rest-assured-version": "${rest-assured.version}", + "compiler-plugin-version": "${compiler-plugin.version}", + "surefire-plugin-version": "${version.surefire.plugin}", + "kotlin-version": "${kotlin.version}", + "scala-version": "${scala.version}", + "scala-plugin-version": "${scala-plugin.version}", + "quarkus-core-version": "${project.version}", + "maven-plugin-groupId": "${project.groupId}", + "maven-plugin-artifactId": "quarkus-maven-plugin", + "maven-plugin-version": "${project.version}", + "gradle-plugin-id": "io.quarkus", + "gradle-plugin-version": "${project.version}", + "supported-maven-versions": "${supported-maven-versions}", + "proposed-maven-version": "${proposed-maven-version}", + "maven-wrapper-version": "${maven-wrapper.version}", + "gradle-wrapper-version": "${gradle-wrapper.version}" + } + }, + "codestarts-artifacts": [ + "${project.groupId}:quarkus-platform-descriptor-json::jar:${project.version}" + ] + } +} \ No newline at end of file diff --git a/devtools/bom-descriptor-json/src/main/resources/extensions-overrides.json b/devtools/bom-descriptor-json/src/main/resources/extensions-overrides.json deleted file mode 100644 index 53c32b86548aca..00000000000000 --- a/devtools/bom-descriptor-json/src/main/resources/extensions-overrides.json +++ /dev/null @@ -1,411 +0,0 @@ -{ - "categories": [ - { - "name": "Core", - "id": "core", - "description": "Essential Quarkus components. Provided automatically" - }, - { - "name": "Web", - "id": "web", - "description": "Everything you need for REST endpoints, HTTP and web formats like JSON", - "metadata": { - "pinned": [ - "io.quarkus:quarkus-resteasy", - "io.quarkus:quarkus-resteasy-jsonb", - "io.quarkus:quarkus-resteasy-jackson" - ] - } - }, - { - "name": "Data", - "id": "data", - "description": "Accessing and managing your data (RDBMS, NoSQL, caching, transaction management, etc)", - "metadata": { - "pinned": [ - "io.quarkus:quarkus-hibernate-orm", - "io.quarkus:quarkus-hibernate-orm-panache", - "io.quarkus:quarkus-jdbc-postgresql", - "io.quarkus:quarkus-jdbc-mariadb", - "io.quarkus:quarkus-jdbc-mysql", - "io.quarkus:quarkus-jdbc-mssql", - "io.quarkus:quarkus-jdbc-h2", - "io.quarkus:quarkus-jdbc-derby" - ] - } - }, - { - "name": "Messaging", - "id": "messaging", - "description": "Send and receives message to various messaging ssytems (AMQP, KAfka etc)", - "metadata": { - "pinned": [ - "io.quarkus:quarkus-smallrye-reactive-messaging", - "io.quarkus:quarkus-smallrye-reactive-messaging-amqp", - "io.quarkus:quarkus-smallrye-reactive-messaging-kafka", - "io.quarkus:quarkus-smallrye-reactive-messaging-mqtt" - ] - } - }, - { - "name": "Reactive", - "id": "reactive", - "description": "Non blocking stack and connectors", - "metadata": { - "pinned": [ - "io.quarkus:quarkus-vertx" - ] - } - }, - { - "name": "Cloud", - "id": "cloud", - "description": "Useful for Cloud Native deployments platforms like Kubernetes and cloud providers", - "metadata": { - "pinned": [ - "io.quarkus:quarkus-kubernetes", - "io.quarkus:quarkus-smallrye-health", - "io.quarkus:quarkus-smallrye-fault-tolerance" - ] - } - }, - { - "name": "Observability", - "id": "observability", - "description": "Metrics, tracing, etc" - }, - { - "name": "Security", - "id": "security", - "description": "Everything you need to secure your application", - "metadata": { - "pinned": [ - "io.quarkus:quarkus-oidc", - "io.quarkus:quarkus-smallrye-jwt" - ] - } - }, - { - "name": "Integration", - "id": "integration", - "description": "Connectors to read to write from a skew of systems (file, S#, Twitter, etc)", - "metadata": { - "pinned": [ - "org.apache.camel.quarkus:camel-quarkus-core", - "org.apache.camel.quarkus:camel-quarkus-core-xml" - ] - } - }, - { - "name": "gRPC", - "id": "grpc", - "description": "gRPC integration", - "metadata": { - "pinned": [ - "io.quarkus:quarkus-grpc" - ] - } - }, - { - "name": "Business Automation", - "id": "business-automation", - "description": "Rules engine, BPM, etc" - }, - { - "name": "Serialization", - "id": "serialization", - "description": "Serializing and deserializing various formats" - }, - { - "name": "Miscellaneous", - "id": "miscellaneous", - "description": "Mixed bag of good stuff" - }, - { - "name": "Compatibility", - "id": "compatibility", - "description": "Support for alternative programming models on Quarkus" - }, - { - "name": "Alternative languages", - "id": "alt-languages", - "description": "Support for other JVM based languages" - } - ], - "extensions": [ - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-support-common", - "version": "0.3.1", - "description": "Camel Quarkus Support Common", - "metadata": { - "unlisted": true - } - }, - { - "metadata": { - "unlisted": true - }, - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-support-jetty", - "version": "0.3.1", - "description": "Camel Quarkus Support Jetty" - }, - { - "metadata": { - "unlisted": true - }, - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-support-xstream", - "version": "0.3.1", - "description": "Camel Quarkus Support XStream" - }, - { - "metadata": { - "unlisted": true - }, - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-support-xml", - "version": "0.3.1", - "description": "Camel Quarkus Support XML" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-core", - "version": "0.3.1", - "description": "The Camel Quarkus core module" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-core-cloud", - "version": "0.3.1", - "description": "The Camel Quarkus core cloud module" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-core-xml", - "version": "0.3.1", - "description": "Camel Quarkus core XML module" - }, - { - "metadata": { - "unlisted": true - }, - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-http-common", - "version": "0.3.1", - "description": "Camel Quarkus HTTP Common" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-aws-eks", - "version": "0.3.1", - "description": "A Camel Amazon EKS Web Service Component" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-aws-s3", - "version": "0.3.1", - "description": "A Camel Amazon S3 Web Service Component" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-aws-sqs", - "version": "0.3.1", - "description": "A Camel Amazon SQS Web Service Component" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-aws-sns", - "version": "0.3.1", - "description": "A Camel Amazon SNS Web Service Component" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-bean", - "version": "0.3.1", - "description": "Camel Bean component" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-csv", - "version": "0.3.1", - "description": "Camel CSV data format support" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-direct", - "version": "0.3.1", - "description": "Camel Direct component" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-fhir", - "version": "0.3.1", - "description": "Camel FHIR HL7 support" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-infinispan", - "version": "0.3.1", - "description": "Camel Infinispan support" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-jackson", - "version": "0.3.1", - "description": "Camel Jackson support" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-jdbc", - "version": "0.3.1", - "description": "Camel JDBC suppors" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-log", - "version": "0.3.1", - "description": "Camel Log component" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-microprofile-health", - "version": "0.3.1", - "description": "Integration with the Quarkus MicroProfile Health extension" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-microprofile-metrics", - "version": "0.3.1", - "description": "Integration with the Quarkus MicroProfile Metrics extension" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-mail", - "version": "0.3.1", - "description": "Camel Mail support" - }, - { - "name": "Camel Quarkus Netty HTTP", - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-netty-http", - "version": "0.3.1", - "description": "Camel Netty HTTP support" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-opentracing", - "version": "0.3.1", - "description": "Distributed tracing using OpenTracing" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-paho", - "version": "0.3.1", - "description": "Camel Eclipse Paho support" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-platform-http", - "version": "0.3.1", - "description": "HTTP platform component is used for integrating Camel HTTP with Quarkus HTTP layer" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-reactive-executor", - "version": "0.3.1", - "description": "Integrates Quarkus reactive executor with Camel" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-rest", - "version": "0.3.1", - "description": "Camel REST component" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-salesforce", - "version": "0.3.1", - "description": "Camel Salesforce support" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-servlet", - "version": "0.3.1", - "description": "Camel servlet transport support" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-slack", - "version": "0.3.1", - "description": "Camel Slack Support" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-tarfile", - "version": "0.3.1", - "description": "Camel Tar file support" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-timer", - "version": "0.3.1", - "description": "Camel Timer component" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-twitter", - "version": "0.3.1", - "description": "Camel Twitter support" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-vm", - "version": "0.3.1", - "description": "Camel VM component" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-zipfile", - "version": "0.3.1", - "description": "Camel Zip file support" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-attachments", - "version": "0.3.1", - "description": "Java Attachments support for Camel Message" - }, - { - "group-id": "org.apache.camel.quarkus", - "artifact-id": "camel-quarkus-pdf", - "version": "0.3.1", - "description": "Camel PDF support" - }, - { - "group-id": "org.kie.kogito", - "artifact-id": "kogito-quarkus", - "version": "0.8.0", - "description": "Kogito extension" - }, - { - "group-id": "org.optaplanner", - "artifact-id": "optaplanner-quarkus", - "version": "7.39.0.CR1", - "description": "OptaPlanner extension" - }, - { - "group-id": "org.optaplanner", - "artifact-id": "optaplanner-quarkus-jackson", - "version": "7.39.0.CR1", - "description": "OptaPlanner Jackson extension" - }, - { - "group-id": "org.optaplanner", - "artifact-id": "optaplanner-quarkus-jsonb", - "version": "7.39.0.CR1", - "description": "OptaPlanner JSON-B extension" - } - ] -} diff --git a/devtools/cli/pom.xml b/devtools/cli/pom.xml index 2ceeff252befcc..582a33a4e773b6 100644 --- a/devtools/cli/pom.xml +++ b/devtools/cli/pom.xml @@ -28,7 +28,8 @@ </dependency> <dependency> <groupId>io.quarkus</groupId> - <artifactId>quarkus-platform-descriptor-resolver-json</artifactId> + <artifactId>quarkus-test-devtools</artifactId> + <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> @@ -57,6 +58,12 @@ </dependencies> <build> + <testResources> + <testResource> + <directory>src/test/resources</directory> + <filtering>true</filtering> + </testResource> + </testResources> <plugins> <plugin> <groupId>io.quarkus</groupId> diff --git a/devtools/cli/src/main/java/io/quarkus/cli/Add.java b/devtools/cli/src/main/java/io/quarkus/cli/Add.java index cfdf010dd7bbfb..8d811879d22569 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/Add.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/Add.java @@ -7,11 +7,12 @@ import io.quarkus.cli.core.BaseSubCommand; import io.quarkus.cli.core.BuildsystemCommand; +import io.quarkus.cli.core.QuarkusCliVersion; import io.quarkus.devtools.commands.AddExtensions; import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; import io.quarkus.devtools.project.BuildTool; import io.quarkus.devtools.project.QuarkusProject; -import io.quarkus.platform.tools.config.QuarkusPlatformConfig; +import io.quarkus.devtools.project.QuarkusProjectHelper; import picocli.CommandLine; @CommandLine.Command(name = "add", usageHelpAutoWidth = true, mixinStandardHelpOptions = false, description = "Add extension(s) to current project.") @@ -47,8 +48,7 @@ public List<String> getArguments(Path projectDir, BuildTool buildtool) { private Integer addMaven(Path projectDirectory) { try { - QuarkusProject quarkusProject = QuarkusProject.resolveExistingProject(projectDirectory, - QuarkusPlatformConfig.getGlobalDefault().getPlatformDescriptor()); + QuarkusProject quarkusProject = QuarkusProjectHelper.getProject(projectDirectory, QuarkusCliVersion.version()); AddExtensions project = new AddExtensions(quarkusProject); project.extensions(extensions); diff --git a/devtools/cli/src/main/java/io/quarkus/cli/Create.java b/devtools/cli/src/main/java/io/quarkus/cli/Create.java index 2f243290421bc8..e14daa927b2ddb 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/Create.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/Create.java @@ -6,10 +6,12 @@ import java.util.concurrent.Callable; import io.quarkus.cli.core.BaseSubCommand; +import io.quarkus.cli.core.QuarkusCliVersion; import io.quarkus.devtools.commands.CreateProject; import io.quarkus.devtools.project.BuildTool; +import io.quarkus.devtools.project.QuarkusProject; +import io.quarkus.devtools.project.QuarkusProjectHelper; import io.quarkus.devtools.project.codegen.SourceType; -import io.quarkus.platform.tools.config.QuarkusPlatformConfig; import picocli.CommandLine; @CommandLine.Command(name = "create", sortOptions = false, usageHelpAutoWidth = true, mixinStandardHelpOptions = false, description = "Create a new quarkus project.") @@ -111,17 +113,17 @@ public Integer call() throws Exception { else if (targetBuildTool.gradleKotlinDsl) buildTool = BuildTool.GRADLE_KOTLIN_DSL; - boolean status = new CreateProject(projectRoot.getAbsoluteFile().toPath(), - QuarkusPlatformConfig.getGlobalDefault().getPlatformDescriptor()) - .buildTool(buildTool) - .groupId(groupId) - .artifactId(artifactId) - .version(version) - .sourceType(sourceType) - .overrideExamples(examples) - .extensions(extensions) - .noExamples(noExamples) - .execute().isSuccess(); + final QuarkusProject project = QuarkusProjectHelper.getProject(projectRoot.getAbsoluteFile().toPath(), buildTool, + QuarkusCliVersion.version()); + boolean status = new CreateProject(project) + .groupId(groupId) + .artifactId(artifactId) + .version(version) + .sourceType(sourceType) + .overrideExamples(examples) + .extensions(extensions) + .noExamples(noExamples) + .execute().isSuccess(); if (status) { out().println("Project " + artifactId + diff --git a/devtools/cli/src/main/java/io/quarkus/cli/CreateJBang.java b/devtools/cli/src/main/java/io/quarkus/cli/CreateJBang.java index 41f3ddbf2cb79a..a922427e0a0201 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/CreateJBang.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/CreateJBang.java @@ -5,8 +5,9 @@ import java.util.concurrent.Callable; import io.quarkus.cli.core.BaseSubCommand; +import io.quarkus.cli.core.QuarkusCliVersion; import io.quarkus.devtools.commands.CreateJBangProject; -import io.quarkus.platform.tools.config.QuarkusPlatformConfig; +import io.quarkus.devtools.project.QuarkusProjectHelper; import picocli.CommandLine; @CommandLine.Command(name = "create-jbang", sortOptions = false, usageHelpAutoWidth = true, mixinStandardHelpOptions = false, description = "Create a new quarkus jbang project.") @@ -35,13 +36,12 @@ public Integer call() throws Exception { return CommandLine.ExitCode.SOFTWARE; } - boolean status = new CreateJBangProject(projectRoot.getAbsoluteFile().toPath(), - QuarkusPlatformConfig.getGlobalDefault().getPlatformDescriptor()) + boolean status = new CreateJBangProject( + QuarkusProjectHelper.getProject(projectRoot.getAbsoluteFile().toPath(), QuarkusCliVersion.version())) .extensions(extensions) .setValue("noJBangWrapper", noJBangWrapper) .execute() .isSuccess(); - if (status) { out().println("JBang project created."); parent.setProjectDirectory(projectRoot.toPath().toAbsolutePath()); diff --git a/devtools/cli/src/main/java/io/quarkus/cli/List.java b/devtools/cli/src/main/java/io/quarkus/cli/List.java index b7665cd44294ed..40e7f09187c6d5 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/List.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/List.java @@ -5,11 +5,11 @@ import io.quarkus.cli.core.BaseSubCommand; import io.quarkus.cli.core.BuildsystemCommand; +import io.quarkus.cli.core.QuarkusCliVersion; import io.quarkus.devtools.commands.ListExtensions; import io.quarkus.devtools.commands.data.QuarkusCommandException; import io.quarkus.devtools.project.BuildTool; -import io.quarkus.devtools.project.QuarkusProject; -import io.quarkus.platform.tools.config.QuarkusPlatformConfig; +import io.quarkus.devtools.project.QuarkusProjectHelper; import picocli.CommandLine; @CommandLine.Command(name = "list", usageHelpAutoWidth = true, sortOptions = false, mixinStandardHelpOptions = false, description = "List installed (default) or installable extensions.") @@ -37,6 +37,10 @@ static class ExtensionFormat { "--full" }, order = 6, description = "Display concise format and version related columns.") boolean full = false; + @CommandLine.Option(names = { + "--origins" }, order = 7, description = "Display extensions including their platform origins.") + boolean origins = false; + } @Override @@ -59,6 +63,8 @@ private String getFormatString() { formatString = "concise"; else if (format.full) formatString = "full"; + else if (format.origins) + formatString = "origins"; return formatString; } @@ -82,14 +88,13 @@ private Integer listExtensionsMaven(Path projectDirectory) { // we do not have to spawn process for maven try { - new ListExtensions(QuarkusProject.resolveExistingProject(projectDirectory, - QuarkusPlatformConfig.getGlobalDefault().getPlatformDescriptor())) - .fromCli(true) - .all(false) - .installed(!installable) - .format(getFormatString()) - .search(searchPattern) - .execute(); + new ListExtensions(QuarkusProjectHelper.getProject(projectDirectory, QuarkusCliVersion.version())) + .fromCli(true) + .all(false) + .installed(!installable) + .format(getFormatString()) + .search(searchPattern) + .execute(); } catch (QuarkusCommandException e) { if (parent.showErrors) e.printStackTrace(err()); diff --git a/devtools/cli/src/main/java/io/quarkus/cli/Platforms.java b/devtools/cli/src/main/java/io/quarkus/cli/Platforms.java new file mode 100644 index 00000000000000..26d056ab48bfb2 --- /dev/null +++ b/devtools/cli/src/main/java/io/quarkus/cli/Platforms.java @@ -0,0 +1,32 @@ +package io.quarkus.cli; + +import java.nio.file.Path; + +import io.quarkus.cli.core.BaseSubCommand; +import io.quarkus.cli.core.BuildsystemCommand; +import io.quarkus.cli.core.QuarkusCliVersion; +import io.quarkus.devtools.commands.ListPlatforms; +import io.quarkus.devtools.project.BuildTool; +import io.quarkus.devtools.project.QuarkusProjectHelper; +import picocli.CommandLine; + +@CommandLine.Command(name = "platforms", usageHelpAutoWidth = true, sortOptions = false, mixinStandardHelpOptions = false, description = "List imported (default) or all available Quarkus platforms.") +public class Platforms extends BaseSubCommand implements BuildsystemCommand { + + @Override + public int execute(Path projectDirectory, BuildTool buildTool) { + try { + new ListPlatforms( + QuarkusProjectHelper.getProject(projectDirectory, buildTool == null ? BuildTool.MAVEN : buildTool, + QuarkusCliVersion.version())) + .execute(); + } catch (Exception e) { + if (parent.showErrors) { + e.printStackTrace(err()); + } + return CommandLine.ExitCode.SOFTWARE; + } + return CommandLine.ExitCode.OK; + } + +} diff --git a/devtools/cli/src/main/java/io/quarkus/cli/QuarkusCli.java b/devtools/cli/src/main/java/io/quarkus/cli/QuarkusCli.java index 00b91bd33ce19f..ab7a18f04dd77d 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/QuarkusCli.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/QuarkusCli.java @@ -10,7 +10,7 @@ import io.quarkus.cli.core.BuildsystemCommand; import io.quarkus.cli.core.ExecuteUtil; -import io.quarkus.cli.core.QuarkusVersion; +import io.quarkus.cli.core.QuarkusCliVersion; import io.quarkus.devtools.project.BuildTool; import io.quarkus.devtools.project.QuarkusProject; import io.quarkus.runtime.QuarkusApplication; @@ -19,9 +19,9 @@ @QuarkusMain @CommandLine.Command(name = "quarkus", aliases = { - "qs" }, versionProvider = QuarkusVersion.class, usageHelpAutoWidth = true, subcommandsRepeatable = true, mixinStandardHelpOptions = true, subcommands = { + "qs" }, versionProvider = QuarkusCliVersion.class, usageHelpAutoWidth = true, subcommandsRepeatable = true, mixinStandardHelpOptions = true, subcommands = { Build.class, - Clean.class, Create.class, CreateJBang.class, List.class, Add.class, Remove.class, Dev.class }) + Clean.class, Create.class, CreateJBang.class, List.class, Platforms.class, Add.class, Remove.class, Dev.class }) public class QuarkusCli implements QuarkusApplication { public void usage() { diff --git a/devtools/cli/src/main/java/io/quarkus/cli/Remove.java b/devtools/cli/src/main/java/io/quarkus/cli/Remove.java index 1eae235d6d981b..b8f1527fddef04 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/Remove.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/Remove.java @@ -7,12 +7,11 @@ import io.quarkus.cli.core.BaseSubCommand; import io.quarkus.cli.core.BuildsystemCommand; +import io.quarkus.cli.core.QuarkusCliVersion; import io.quarkus.devtools.commands.RemoveExtensions; import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; import io.quarkus.devtools.project.BuildTool; -import io.quarkus.devtools.project.QuarkusProject; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.tools.config.QuarkusPlatformConfig; +import io.quarkus.devtools.project.QuarkusProjectHelper; import picocli.CommandLine; @CommandLine.Command(name = "remove", aliases = "rm", usageHelpAutoWidth = true, mixinStandardHelpOptions = false, description = "Remove an extension from this project.") @@ -48,10 +47,10 @@ public int execute(Path projectDir, BuildTool buildtool) throws Exception { } private Integer removeMaven(Path projectDirectory) { - final QuarkusPlatformDescriptor platformDescr = QuarkusPlatformConfig.getGlobalDefault().getPlatformDescriptor(); try { - RemoveExtensions project = new RemoveExtensions(QuarkusProject.resolveExistingProject(projectDirectory, - platformDescr)).extensions(extensions); + RemoveExtensions project = new RemoveExtensions( + QuarkusProjectHelper.getProject(projectDirectory, QuarkusCliVersion.version())) + .extensions(extensions); QuarkusCommandOutcome result = project.execute(); return result.isSuccess() ? CommandLine.ExitCode.OK : CommandLine.ExitCode.SOFTWARE; } catch (Exception e) { diff --git a/devtools/cli/src/main/java/io/quarkus/cli/core/ExecuteUtil.java b/devtools/cli/src/main/java/io/quarkus/cli/core/ExecuteUtil.java index 7ad2d14dcc7259..eb1f618b9b4136 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/core/ExecuteUtil.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/core/ExecuteUtil.java @@ -18,6 +18,7 @@ import io.quarkus.cli.QuarkusCli; import io.quarkus.devtools.project.BuildTool; +import io.quarkus.registry.config.RegistriesConfigLocator; import io.quarkus.utilities.OS; import picocli.CommandLine; @@ -173,9 +174,9 @@ public static int executeGradleTarget(File projectPath, QuarkusCli cli, String.. return SOFTWARE; } String[] newArgs = args; - if (System.getProperties().containsKey("maven.repo.local")) { - newArgs = prependArray("-Dmaven.repo.local=" + System.getProperty("maven.repo.local"), newArgs); - } + newArgs = propagatePropertyIfSet("maven.repo.local", newArgs); + newArgs = propagatePropertyIfSet(RegistriesConfigLocator.CONFIG_FILE_PATH_PROPERTY, newArgs); + newArgs = propagatePropertyIfSet("io.quarkus.maven.secondary-local-repo", newArgs); if (cli.isShowErrors()) { newArgs = prependArray("--full-stacktrace", newArgs); } @@ -189,6 +190,11 @@ public static int executeGradleTarget(File projectPath, QuarkusCli cli, String.. } } + private static String[] propagatePropertyIfSet(String name, String[] newArgs) { + final String value = System.getProperty(name); + return value == null ? newArgs : prependArray("-D" + name + "=" + value, newArgs); + } + public static int executeMavenTarget(File projectPath, QuarkusCli cli, String... args) throws Exception { File buildFile = projectPath.toPath().resolve("pom.xml").toFile(); if (!buildFile.isFile()) { diff --git a/devtools/cli/src/main/java/io/quarkus/cli/core/QuarkusCliVersion.java b/devtools/cli/src/main/java/io/quarkus/cli/core/QuarkusCliVersion.java new file mode 100644 index 00000000000000..60ad015fa716c4 --- /dev/null +++ b/devtools/cli/src/main/java/io/quarkus/cli/core/QuarkusCliVersion.java @@ -0,0 +1,44 @@ +package io.quarkus.cli.core; + +import java.io.BufferedReader; +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.util.Properties; + +import io.smallrye.common.classloader.ClassPathUtils; +import picocli.CommandLine; + +public class QuarkusCliVersion implements CommandLine.IVersionProvider { + + private static String version; + + public static String version() { + if (version != null) { + return version; + } + final URL quarkusPropsUrl = Thread.currentThread().getContextClassLoader().getResource("quarkus.properties"); + if (quarkusPropsUrl == null) { + throw new RuntimeException("Failed to locate quarkus.properties on the classpath"); + } + final Properties props = new Properties(); + ClassPathUtils.consumeAsPath(quarkusPropsUrl, p -> { + try (BufferedReader reader = Files.newBufferedReader(p)) { + props.load(reader); + } catch (IOException e) { + throw new RuntimeException("Failed to load quarkus.properties", e); + } + }); + version = props.getProperty("quarkus-core-version"); + if (version == null) { + throw new RuntimeException("Failed to locate quarkus-core-version property in the bundled quarkus.properties"); + } + return version; + } + + @Override + public String[] getVersion() throws Exception { + return new String[] { version() }; + } + +} diff --git a/devtools/cli/src/main/java/io/quarkus/cli/core/QuarkusVersion.java b/devtools/cli/src/main/java/io/quarkus/cli/core/QuarkusVersion.java index 8e710d9c1ae1d5..e3ebfbc3c6dfb9 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/core/QuarkusVersion.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/core/QuarkusVersion.java @@ -1,12 +1,15 @@ package io.quarkus.cli.core; -import io.quarkus.platform.tools.config.QuarkusPlatformConfig; +import java.nio.file.Paths; + +import io.quarkus.devtools.project.QuarkusProjectHelper; import picocli.CommandLine; public class QuarkusVersion implements CommandLine.IVersionProvider { @Override public String[] getVersion() throws Exception { - return new String[] { QuarkusPlatformConfig.getGlobalDefault().getPlatformDescriptor().getQuarkusVersion() }; + return new String[] { QuarkusProjectHelper.getProject(Paths.get("").normalize().toAbsolutePath()).getExtensionsCatalog() + .getQuarkusCoreVersion() }; } } diff --git a/devtools/cli/src/test/java/io/quarkus/cli/CliTest.java b/devtools/cli/src/test/java/io/quarkus/cli/CliTest.java index 89d34244c5c841..bd0f7cfaa823f7 100644 --- a/devtools/cli/src/test/java/io/quarkus/cli/CliTest.java +++ b/devtools/cli/src/test/java/io/quarkus/cli/CliTest.java @@ -8,12 +8,15 @@ import java.nio.file.Paths; import java.util.Comparator; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import io.quarkus.cli.core.ExecuteUtil; +import io.quarkus.devtools.test.DevToolsRegistryTestHelper; import picocli.CommandLine; public class CliTest { @@ -24,6 +27,16 @@ public class CliTest { private String cwd; private Path workspace; + @BeforeAll + public static void globalSetup() { + DevToolsRegistryTestHelper.enableDevToolsTestConfig(); + } + + @AfterAll + public static void globalReset() { + DevToolsRegistryTestHelper.disableDevToolsTestConfig(); + } + @BeforeEach public void setupTestDirectories() throws Exception { cwd = System.getProperty("user.dir"); @@ -32,7 +45,6 @@ public void setupTestDirectories() throws Exception { Assertions.assertFalse(workspace.toFile().exists()); Files.createDirectories(workspace); System.setProperty("user.dir", workspace.toFile().getAbsolutePath()); - } @AfterEach diff --git a/devtools/gradle/build.gradle b/devtools/gradle/build.gradle index 30e74d42792018..e55bfd1ad8d18f 100644 --- a/devtools/gradle/build.gradle +++ b/devtools/gradle/build.gradle @@ -27,17 +27,12 @@ repositories { mavenCentral() } -configurations.all { - exclude group: 'io.quarkus', module: 'quarkus-bootstrap-maven-resolver' -} - dependencies { api gradleApi() implementation "io.quarkus:quarkus-bootstrap-core:${version}" implementation "io.quarkus:quarkus-devtools-common:${version}" implementation "io.quarkus:quarkus-platform-descriptor-json:${version}" - implementation "io.quarkus:quarkus-platform-descriptor-resolver-json:${version}" implementation "io.quarkus:quarkus-core-deployment:${version}" testImplementation 'org.mockito:mockito-core:3.8.0' diff --git a/devtools/gradle/pom.xml b/devtools/gradle/pom.xml index 870b117142b9c2..cfc5f3bf44de11 100644 --- a/devtools/gradle/pom.xml +++ b/devtools/gradle/pom.xml @@ -45,10 +45,6 @@ <groupId>io.quarkus</groupId> <artifactId>quarkus-platform-descriptor-json</artifactId> </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-platform-descriptor-resolver-json</artifactId> - </dependency> <dependency> <groupId>org.awaitility</groupId> <artifactId>awaitility</artifactId> diff --git a/devtools/gradle/src/main/java/io/quarkus/devtools/project/buildfile/GradleGroovyProjectBuildFile.java b/devtools/gradle/src/main/java/io/quarkus/devtools/project/buildfile/GradleGroovyProjectBuildFile.java index 8ad02f5e780d5e..66a9f7449076df 100644 --- a/devtools/gradle/src/main/java/io/quarkus/devtools/project/buildfile/GradleGroovyProjectBuildFile.java +++ b/devtools/gradle/src/main/java/io/quarkus/devtools/project/buildfile/GradleGroovyProjectBuildFile.java @@ -4,15 +4,15 @@ import io.quarkus.bootstrap.model.AppArtifactCoords; import io.quarkus.devtools.project.BuildTool; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.registry.catalog.ExtensionCatalog; public class GradleGroovyProjectBuildFile extends GradleProjectBuildFile { static final String BUILD_GRADLE_PATH = "build.gradle"; static final String SETTINGS_GRADLE_PATH = "settings.gradle"; - public GradleGroovyProjectBuildFile(Project project, QuarkusPlatformDescriptor platformDescriptor) { - super(project, platformDescriptor); + public GradleGroovyProjectBuildFile(Project project, ExtensionCatalog catalog) { + super(project, catalog); } @Override diff --git a/devtools/gradle/src/main/java/io/quarkus/devtools/project/buildfile/GradleKotlinProjectBuildFile.java b/devtools/gradle/src/main/java/io/quarkus/devtools/project/buildfile/GradleKotlinProjectBuildFile.java index cafc67675528fa..4ca9db743ea10d 100644 --- a/devtools/gradle/src/main/java/io/quarkus/devtools/project/buildfile/GradleKotlinProjectBuildFile.java +++ b/devtools/gradle/src/main/java/io/quarkus/devtools/project/buildfile/GradleKotlinProjectBuildFile.java @@ -4,15 +4,15 @@ import io.quarkus.bootstrap.model.AppArtifactCoords; import io.quarkus.devtools.project.BuildTool; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.registry.catalog.ExtensionCatalog; public class GradleKotlinProjectBuildFile extends GradleProjectBuildFile { static final String BUILD_GRADLE_PATH = "build.gradle.kts"; static final String SETTINGS_GRADLE_PATH = "settings.gradle.kts"; - public GradleKotlinProjectBuildFile(Project project, QuarkusPlatformDescriptor platformDescriptor) { - super(project, platformDescriptor); + public GradleKotlinProjectBuildFile(Project project, ExtensionCatalog catalog) { + super(project, catalog); } @Override diff --git a/devtools/gradle/src/main/java/io/quarkus/devtools/project/buildfile/GradleProjectBuildFile.java b/devtools/gradle/src/main/java/io/quarkus/devtools/project/buildfile/GradleProjectBuildFile.java index bc9dbccb3e4f20..2ae31c87f2d614 100644 --- a/devtools/gradle/src/main/java/io/quarkus/devtools/project/buildfile/GradleProjectBuildFile.java +++ b/devtools/gradle/src/main/java/io/quarkus/devtools/project/buildfile/GradleProjectBuildFile.java @@ -15,14 +15,14 @@ import org.gradle.api.plugins.JavaPlugin; import io.quarkus.bootstrap.model.AppArtifactCoords; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.registry.catalog.ExtensionCatalog; public abstract class GradleProjectBuildFile extends AbstractGradleBuildFile { private final Project project; - public GradleProjectBuildFile(Project project, QuarkusPlatformDescriptor platformDescriptor) { - super(project.getProjectDir().toPath(), platformDescriptor, + public GradleProjectBuildFile(Project project, ExtensionCatalog catalog) { + super(project.getProjectDir().toPath(), catalog, project.getParent() != null ? project.getRootProject().getProjectDir().toPath() : project.getProjectDir().toPath()); this.project = project; diff --git a/devtools/gradle/src/main/java/io/quarkus/gradle/AppModelGradleResolver.java b/devtools/gradle/src/main/java/io/quarkus/gradle/AppModelGradleResolver.java index f9fa9d7fb7ab50..4760563d618ae3 100644 --- a/devtools/gradle/src/main/java/io/quarkus/gradle/AppModelGradleResolver.java +++ b/devtools/gradle/src/main/java/io/quarkus/gradle/AppModelGradleResolver.java @@ -7,6 +7,7 @@ import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; +import org.gradle.api.artifacts.ResolveException; import org.gradle.api.artifacts.ResolvedArtifact; import org.gradle.api.artifacts.ResolvedConfiguration; import org.gradle.api.internal.artifacts.dependencies.DefaultDependencyArtifact; @@ -35,12 +36,23 @@ public AppModelGradleResolver(Project project, QuarkusModel model) { @Override public String getLatestVersion(AppArtifact appArtifact, String upToVersion, boolean inclusive) throws AppModelResolverException { - throw new UnsupportedOperationException(); + try { + return resolveArtifact(new AppArtifact(appArtifact.getGroupId(), appArtifact.getArtifactId(), + appArtifact.getClassifier(), appArtifact.getType(), + "[" + appArtifact.getVersion() + "," + upToVersion + (inclusive ? "]" : ")"))).getVersion(); + } catch (AppModelResolverException e) { + return null; + } } @Override public String getLatestVersionFromRange(AppArtifact appArtifact, String range) throws AppModelResolverException { - throw new UnsupportedOperationException(); + try { + return resolveArtifact(new AppArtifact(appArtifact.getGroupId(), appArtifact.getArtifactId(), + appArtifact.getClassifier(), appArtifact.getType(), range)).getVersion(); + } catch (AppModelResolverException e) { + return null; + } } @Override @@ -63,40 +75,52 @@ public void relink(AppArtifact appArtifact, Path localPath) throws AppModelResol @Override public Path resolve(AppArtifact appArtifact) throws AppModelResolverException { - if (!appArtifact.isResolved()) { - final DefaultDependencyArtifact dep = new DefaultDependencyArtifact(); - dep.setExtension(appArtifact.getType()); - dep.setType(appArtifact.getType()); - dep.setName(appArtifact.getArtifactId()); - if (appArtifact.getClassifier() != null) { - dep.setClassifier(appArtifact.getClassifier()); - } + return resolveArtifact(appArtifact).getPaths().getSinglePath(); + } - final DefaultExternalModuleDependency gradleDep = new DefaultExternalModuleDependency(appArtifact.getGroupId(), - appArtifact.getArtifactId(), appArtifact.getVersion(), null); - gradleDep.addArtifact(dep); - - final Configuration detachedConfig = project.getConfigurations().detachedConfiguration(gradleDep); - - final ResolvedConfiguration rc = detachedConfig.getResolvedConfiguration(); - Set<ResolvedArtifact> resolvedArtifacts = rc.getResolvedArtifacts(); - for (ResolvedArtifact a : resolvedArtifacts) { - if (appArtifact.getArtifactId().equals(a.getName()) - && appArtifact.getType().equals(a.getType()) - && (a.getClassifier() == null ? appArtifact.getClassifier() == null - : a.getClassifier().equals(appArtifact.getClassifier())) - && appArtifact.getGroupId().equals(a.getModuleVersion().getId().getGroup())) { - appArtifact.setPath(a.getFile().toPath()); - break; - } - } + private AppArtifact resolveArtifact(AppArtifact appArtifact) throws AppModelResolverException { + if (appArtifact.isResolved()) { + return appArtifact; + } + final DefaultDependencyArtifact dep = new DefaultDependencyArtifact(); + dep.setExtension(appArtifact.getType()); + dep.setType(appArtifact.getType()); + dep.setName(appArtifact.getArtifactId()); + if (appArtifact.getClassifier() != null) { + dep.setClassifier(appArtifact.getClassifier()); + } + + final DefaultExternalModuleDependency gradleDep = new DefaultExternalModuleDependency(appArtifact.getGroupId(), + appArtifact.getArtifactId(), appArtifact.getVersion(), null); + gradleDep.addArtifact(dep); - if (!appArtifact.isResolved()) { - throw new AppModelResolverException("Failed to resolve " + appArtifact); + final Configuration detachedConfig = project.getConfigurations().detachedConfiguration(gradleDep); + + final ResolvedConfiguration rc = detachedConfig.getResolvedConfiguration(); + Set<ResolvedArtifact> resolvedArtifacts; + try { + resolvedArtifacts = rc.getResolvedArtifacts(); + } catch (ResolveException e) { + throw new AppModelResolverException("Failed to resolve " + appArtifact, e); + } + for (ResolvedArtifact a : resolvedArtifacts) { + if (appArtifact.getArtifactId().equals(a.getName()) && appArtifact.getType().equals(a.getType()) + && (a.getClassifier() == null ? appArtifact.getClassifier() == null + : a.getClassifier().equals(appArtifact.getClassifier())) + && appArtifact.getGroupId().equals(a.getModuleVersion().getId().getGroup())) { + if (!appArtifact.getVersion().equals(a.getModuleVersion().getId().getVersion())) { + appArtifact = new AppArtifact(appArtifact.getGroupId(), appArtifact.getArtifactId(), + appArtifact.getClassifier(), appArtifact.getType(), a.getModuleVersion().getId().getVersion()); + } + appArtifact.setPath(a.getFile().toPath()); + break; } + } + if (!appArtifact.isResolved()) { + throw new AppModelResolverException("Failed to resolve " + appArtifact); } - return appArtifact.getPaths().getSinglePath(); + return appArtifact; } @Override @@ -129,5 +153,4 @@ public AppModel resolveManagedModel(AppArtifact appArtifact, List<AppDependency> throws AppModelResolverException { return resolveModel(appArtifact); } - } diff --git a/devtools/gradle/src/main/java/io/quarkus/gradle/QuarkusPlugin.java b/devtools/gradle/src/main/java/io/quarkus/gradle/QuarkusPlugin.java index 3d3b31f50b1b16..331a0027870e5d 100644 --- a/devtools/gradle/src/main/java/io/quarkus/gradle/QuarkusPlugin.java +++ b/devtools/gradle/src/main/java/io/quarkus/gradle/QuarkusPlugin.java @@ -39,6 +39,7 @@ import io.quarkus.gradle.tasks.QuarkusGenerateCode; import io.quarkus.gradle.tasks.QuarkusGenerateConfig; import io.quarkus.gradle.tasks.QuarkusListExtensions; +import io.quarkus.gradle.tasks.QuarkusListPlatforms; import io.quarkus.gradle.tasks.QuarkusRemoteDev; import io.quarkus.gradle.tasks.QuarkusRemoveExtension; import io.quarkus.gradle.tasks.QuarkusTestConfig; @@ -51,6 +52,7 @@ public class QuarkusPlugin implements Plugin<Project> { public static final String EXTENSION_NAME = "quarkus"; public static final String LIST_EXTENSIONS_TASK_NAME = "listExtensions"; + public static final String LIST_PLATFORMS_TASK_NAME = "listPlatforms"; public static final String ADD_EXTENSION_TASK_NAME = "addExtension"; public static final String REMOVE_EXTENSION_TASK_NAME = "removeExtension"; public static final String QUARKUS_GENERATE_CODE_TASK_NAME = "quarkusGenerateCode"; @@ -90,10 +92,10 @@ public void apply(Project project) { registerTasks(project, quarkusExt); } - @SuppressWarnings("Convert2Lambda") private void registerTasks(Project project, QuarkusPluginExtension quarkusExt) { TaskContainer tasks = project.getTasks(); tasks.create(LIST_EXTENSIONS_TASK_NAME, QuarkusListExtensions.class); + tasks.create(LIST_PLATFORMS_TASK_NAME, QuarkusListPlatforms.class); tasks.create(ADD_EXTENSION_TASK_NAME, QuarkusAddExtension.class); tasks.create(REMOVE_EXTENSION_TASK_NAME, QuarkusRemoveExtension.class); tasks.create(GENERATE_CONFIG_TASK_NAME, QuarkusGenerateConfig.class); diff --git a/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusAddExtension.java b/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusAddExtension.java index cab182f13f01e2..2639c3cdfbbc2d 100644 --- a/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusAddExtension.java +++ b/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusAddExtension.java @@ -1,21 +1,17 @@ package io.quarkus.gradle.tasks; import static java.util.Arrays.stream; -import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toSet; -import java.net.URL; import java.util.List; import java.util.Set; import org.gradle.api.GradleException; import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.Optional; import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.options.Option; import io.quarkus.devtools.commands.AddExtensions; -import io.quarkus.registry.DefaultExtensionRegistry; public class QuarkusAddExtension extends QuarkusPlatformTask { @@ -24,7 +20,6 @@ public QuarkusAddExtension() { } private List<String> extensionsToAdd; - private List<String> registries; @Option(option = "extensions", description = "Configures the extensions to be added.") public void setExtensionsToAdd(List<String> extensionsToAdd) { @@ -36,17 +31,6 @@ public List<String> getExtensionsToAdd() { return extensionsToAdd; } - @Optional - @Input - public List<String> getRegistries() { - return registries; - } - - @Option(description = "The extension registry URLs to be used", option = "registry") - public void setRegistries(List<String> registry) { - this.registries = registry; - } - @TaskAction public void addExtension() { Set<String> extensionsSet = getExtensionsToAdd() @@ -56,14 +40,8 @@ public void addExtension() { .collect(toSet()); try { - AddExtensions addExtensions = new AddExtensions(getQuarkusProject()) + AddExtensions addExtensions = new AddExtensions(getQuarkusProject(false)) .extensions(extensionsSet); - if (registries != null && !registries.isEmpty()) { - List<URL> urls = registries.stream() - .map(QuarkusAddExtension::toURL) - .collect(toList()); - addExtensions.extensionRegistry(DefaultExtensionRegistry.fromURLs(urls)); - } addExtensions.execute(); } catch (Exception e) { throw new GradleException("Failed to add extensions " + getExtensionsToAdd(), e); diff --git a/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusListExtensions.java b/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusListExtensions.java index 97c29f1261475b..428f0f4d932ae6 100644 --- a/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusListExtensions.java +++ b/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusListExtensions.java @@ -1,10 +1,5 @@ package io.quarkus.gradle.tasks; -import static java.util.stream.Collectors.toList; - -import java.net.URL; -import java.util.List; - import org.gradle.api.GradleException; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Optional; @@ -13,7 +8,6 @@ import io.quarkus.devtools.commands.ListExtensions; import io.quarkus.devtools.project.QuarkusProject; -import io.quarkus.registry.DefaultExtensionRegistry; public class QuarkusListExtensions extends QuarkusPlatformTask { @@ -25,8 +19,6 @@ public class QuarkusListExtensions extends QuarkusPlatformTask { private String searchPattern; - private List<String> registries; - @Input public boolean isAll() { return all; @@ -79,17 +71,6 @@ public void setSearchPattern(String searchPattern) { this.searchPattern = searchPattern; } - @Optional - @Input - public List<String> getRegistries() { - return registries; - } - - @Option(description = "The extension registry URLs to be used", option = "registry") - public void setRegistries(List<String> registry) { - this.registries = registry; - } - public QuarkusListExtensions() { super("Lists the available quarkus extensions"); } @@ -97,22 +78,13 @@ public QuarkusListExtensions() { @TaskAction public void listExtensions() { try { - final QuarkusProject quarkusProject = getQuarkusProject(); - getLogger().info("Quarkus platform " + quarkusProject.getPlatformDescriptor().getBomGroupId() + ":" - + quarkusProject.getPlatformDescriptor().getBomArtifactId() + ":" - + quarkusProject.getPlatformDescriptor().getBomVersion()); + final QuarkusProject quarkusProject = getQuarkusProject(installed); ListExtensions listExtensions = new ListExtensions(quarkusProject) .all(isFromCli() ? false : isAll()) .fromCli(isFromCli()) .format(getFormat()) .installed(isInstalled()) .search(getSearchPattern()); - if (registries != null && !registries.isEmpty()) { - List<URL> urls = registries.stream() - .map(QuarkusListExtensions::toURL) - .collect(toList()); - listExtensions.extensionRegistry(DefaultExtensionRegistry.fromURLs(urls)); - } listExtensions.execute(); } catch (Exception e) { throw new GradleException("Unable to list extensions", e); diff --git a/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusListPlatforms.java b/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusListPlatforms.java new file mode 100644 index 00000000000000..ae671f78c16c94 --- /dev/null +++ b/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusListPlatforms.java @@ -0,0 +1,52 @@ +package io.quarkus.gradle.tasks; + +import org.gradle.api.GradleException; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.TaskAction; +import org.gradle.api.tasks.options.Option; + +import io.quarkus.devtools.commands.ListPlatforms; +import io.quarkus.registry.Constants; + +public class QuarkusListPlatforms extends QuarkusPlatformTask { + + private boolean installed = false; + + public QuarkusListPlatforms() { + super("Lists the available quarkus platforms"); + } + + @Input + public boolean isInstalled() { + return installed; + } + + @Option(description = "List only installed platforms.", option = "installed") + public void setInstalled(boolean installed) { + this.installed = installed; + } + + @TaskAction + public void listExtensions() { + getProject().getLogger().info(""); + if (installed) { + getProject().getLogger().info("Imported Quarkus platforms:"); + importedPlatforms().forEach(coords -> { + final StringBuilder buf = new StringBuilder(); + buf.append(coords.getGroupId()).append(":") + .append(coords.getArtifactId().substring(0, + coords.getArtifactId().length() - Constants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX.length())) + .append("::pom:").append(coords.getVersion()); + messageWriter().info(buf.toString()); + }); + } else { + getProject().getLogger().info("Available Quarkus platforms:"); + try { + new ListPlatforms(getQuarkusProject(installed)).execute(); + } catch (Exception e) { + throw new GradleException("Unable to list platforms", e); + } + } + getProject().getLogger().info(""); + } +} diff --git a/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusPlatformTask.java b/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusPlatformTask.java index 6631109480881d..c3905b83dadb6b 100644 --- a/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusPlatformTask.java +++ b/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusPlatformTask.java @@ -8,28 +8,27 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; import org.gradle.api.GradleException; -import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.Dependency; import org.gradle.api.artifacts.ModuleDependency; -import org.gradle.api.artifacts.ResolvedArtifact; import org.gradle.api.attributes.Category; -import org.gradle.api.internal.artifacts.dependencies.DefaultDependencyArtifact; -import org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency; import org.gradle.api.plugins.JavaPlugin; -import org.gradle.api.tasks.Internal; import io.quarkus.bootstrap.BootstrapConstants; import io.quarkus.bootstrap.model.AppArtifactKey; +import io.quarkus.devtools.messagewriter.MessageWriter; import io.quarkus.devtools.project.QuarkusProject; +import io.quarkus.devtools.project.QuarkusProjectHelper; import io.quarkus.devtools.project.buildfile.BuildFile; import io.quarkus.devtools.project.buildfile.GradleGroovyProjectBuildFile; import io.quarkus.devtools.project.buildfile.GradleKotlinProjectBuildFile; -import io.quarkus.platform.descriptor.CombinedQuarkusPlatformDescriptor; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.descriptor.resolver.json.QuarkusJsonPlatformDescriptorResolver; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.platform.tools.ToolsUtils; +import io.quarkus.registry.ExtensionCatalogResolver; +import io.quarkus.registry.catalog.ExtensionCatalog; public abstract class QuarkusPlatformTask extends QuarkusTask { @@ -37,35 +36,70 @@ public abstract class QuarkusPlatformTask extends QuarkusTask { super(description); } - protected QuarkusPlatformDescriptor platformDescriptor() { + private ExtensionCatalog extensionsCatalog(boolean limitExtensionsToImportedPlatforms, MessageWriter log) { + final List<ArtifactCoords> platforms = importedPlatforms(); + final ExtensionCatalogResolver catalogResolver = QuarkusProjectHelper.getCatalogResolver(log); + if (catalogResolver.hasRegistries()) { + try { + return limitExtensionsToImportedPlatforms ? catalogResolver.resolveExtensionCatalog(platforms) + : catalogResolver.resolveExtensionCatalog(quarkusCoreVersion()); + } catch (Exception e) { + throw new RuntimeException("Failed to resolve extensions catalog", e); + } + } + return ToolsUtils.mergePlatforms(platforms, extension().getAppModelResolver()); + } - final List<Dependency> boms = boms(); - if (boms.isEmpty()) { + protected List<ArtifactCoords> importedPlatforms() { + final List<Dependency> bomDeps = boms(); + if (bomDeps.isEmpty()) { throw new GradleException("No platforms detected in the project"); } - final QuarkusJsonPlatformDescriptorResolver platformResolver = QuarkusJsonPlatformDescriptorResolver.newInstance() - .setArtifactResolver(extension().getAppModelResolver()) - .setMessageWriter(new GradleMessageWriter(getProject().getLogger())); + final Configuration boms = getProject().getConfigurations() + .detachedConfiguration(bomDeps.toArray(new org.gradle.api.artifacts.Dependency[0])); + final Set<AppArtifactKey> processedKeys = new HashSet<>(1); - final QuarkusPlatformDescriptor platform = resolvePlatformDescriptor(platformResolver, getProject(), boms); - if (platform != null) { - return platform; - } + List<ArtifactCoords> platforms = new ArrayList<>(); + boms.getResolutionStrategy().eachDependency(d -> { + if (!d.getTarget().getName().endsWith(BootstrapConstants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX) + || !processedKeys.add(new AppArtifactKey(d.getTarget().getGroup(), d.getTarget().getName()))) { + return; + } + final ArtifactCoords platform = new ArtifactCoords(d.getTarget().getGroup(), d.getTarget().getName(), + d.getTarget().getVersion(), "json", d.getTarget().getVersion()); + platforms.add(platform); + }); + boms.getResolvedConfiguration(); - final List<QuarkusPlatformDescriptor> platforms = resolveLegacyPlatforms(platformResolver, boms); if (platforms.isEmpty()) { - throw new GradleException("Failed to determine the Quarkus platform for the project"); + throw new RuntimeException("No Quarkus platforms found in the project"); } - if (platforms.size() == 1) { - return platforms.get(0); + return platforms; + } + + protected String quarkusCoreVersion() { + final List<Dependency> bomDeps = boms(); + if (bomDeps.isEmpty()) { + throw new GradleException("No platforms detected in the project"); } - final CombinedQuarkusPlatformDescriptor.Builder builder = CombinedQuarkusPlatformDescriptor.builder(); - for (QuarkusPlatformDescriptor descriptor : platforms) { - builder.addPlatform(descriptor); + final Configuration boms = getProject().getConfigurations() + .detachedConfiguration(bomDeps.toArray(new org.gradle.api.artifacts.Dependency[0])); + + final AtomicReference<String> quarkusVersionRef = new AtomicReference<>(); + boms.getResolutionStrategy().eachDependency(d -> { + if (quarkusVersionRef.get() == null && d.getTarget().getName().equals("quarkus-core") + && d.getTarget().getGroup().equals("io.quarkus")) { + quarkusVersionRef.set(d.getTarget().getVersion()); + } + }); + boms.getResolvedConfiguration(); + final String quarkusCoreVersion = quarkusVersionRef.get(); + if (quarkusCoreVersion == null) { + throw new IllegalStateException("Failed to determine the Quarkus core version for the project"); } - return builder.build(); + return quarkusCoreVersion; } private List<Dependency> boms() { @@ -87,99 +121,10 @@ private List<Dependency> boms() { return boms; } - private List<QuarkusPlatformDescriptor> resolveLegacyPlatforms( - QuarkusJsonPlatformDescriptorResolver platformResolver, - List<Dependency> boms) { - List<QuarkusPlatformDescriptor> platforms = new ArrayList<>(2); - boms.forEach(bom -> { - try { - platforms - .add(platformResolver.resolveFromBom(bom.getGroup(), bom.getName(), bom.getVersion())); - } catch (Exception e) { - // not a platform - } - }); - return platforms; - } + protected QuarkusProject getQuarkusProject(boolean limitExtensionsToImportedPlatforms) { - private QuarkusPlatformDescriptor resolvePlatformDescriptor(QuarkusJsonPlatformDescriptorResolver descriptorResolver, - Project project, List<Dependency> bomDeps) { - final Configuration boms = project.getConfigurations() - .detachedConfiguration(bomDeps.toArray(new org.gradle.api.artifacts.Dependency[0])); - final Set<AppArtifactKey> processedKeys = new HashSet<>(1); - final List<ResolvedArtifact> descriptorDeps = new ArrayList<>(2); - boms.getResolutionStrategy().eachDependency(d -> { - if (!d.getTarget().getName().endsWith(BootstrapConstants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX) - || !processedKeys.add(new AppArtifactKey(d.getTarget().getGroup(), d.getTarget().getName()))) { - return; - } - - final DefaultDependencyArtifact dep = new DefaultDependencyArtifact(); - dep.setExtension("json"); - dep.setType("json"); - dep.setClassifier(d.getTarget().getVersion()); - dep.setName(d.getTarget().getName()); - - final DefaultExternalModuleDependency gradleDep = new DefaultExternalModuleDependency( - d.getTarget().getGroup(), d.getTarget().getName(), d.getTarget().getVersion(), null); - gradleDep.addArtifact(dep); - - try { - for (ResolvedArtifact a : project.getConfigurations().detachedConfiguration(gradleDep) - .getResolvedConfiguration().getResolvedArtifacts()) { - if (a.getName().equals(d.getTarget().getName())) { - descriptorDeps.add(a); - break; - } - } - } catch (Exception e) { - // ignore for now - } - }); - boms.getResolvedConfiguration(); - - if (descriptorDeps.isEmpty()) { - return null; - } - if (descriptorDeps.size() == 1) { - return descriptorResolver.resolveFromJson(descriptorDeps.get(0).getFile().toPath()); - } - - // Typically, quarkus-bom platform will appear first. - // The descriptors that are generated today are not fragmented and include everything - // a platform offers. Which means if the quarkus-bom platform appears first and its version - // matches the Quarkus core version of the platform built on top of the quarkus-bom - // (e.g. quarkus-universe-bom) the quarkus-bom platform can be skipped, - // since it will already be included in the platform that's built on top of it - int i = 0; - ResolvedArtifact platformArtifact = descriptorDeps.get(0); - final String quarkusBomPlatformArtifactId = "quarkus-bom-" - + BootstrapConstants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX; - ResolvedArtifact quarkusBomPlatformArtifact = null; - if (quarkusBomPlatformArtifactId.equals(platformArtifact.getName())) { - quarkusBomPlatformArtifact = platformArtifact; - } - final CombinedQuarkusPlatformDescriptor.Builder builder = CombinedQuarkusPlatformDescriptor.builder(); - while (++i < descriptorDeps.size()) { - platformArtifact = descriptorDeps.get(i); - final QuarkusPlatformDescriptor descriptor = descriptorResolver - .resolveFromJson(platformArtifact.getFile().toPath()); - if (quarkusBomPlatformArtifact != null) { - if (!quarkusBomPlatformArtifact.getModuleVersion().getId().getVersion() - .equals(descriptor.getQuarkusVersion())) { - builder.addPlatform(descriptorResolver.resolveFromJson(quarkusBomPlatformArtifact.getFile().toPath())); - } - quarkusBomPlatformArtifact = null; - } - builder.addPlatform(descriptorResolver.resolveFromJson(platformArtifact.getFile().toPath())); - } - return builder.build(); - } - - @Internal - protected QuarkusProject getQuarkusProject() { - - final QuarkusPlatformDescriptor platformDescriptor = platformDescriptor(); + final GradleMessageWriter log = messageWriter(); + final ExtensionCatalog catalog = extensionsCatalog(limitExtensionsToImportedPlatforms, log); final Path projectDirPath = getProject().getProjectDir().toPath(); final Path rootProjectPath = getProject().getParent() != null ? getProject().getRootProject().getProjectDir().toPath() @@ -187,15 +132,19 @@ protected QuarkusProject getQuarkusProject() { final BuildFile buildFile; if (Files.exists(rootProjectPath.resolve("settings.gradle.kts")) && Files.exists(projectDirPath.resolve("build.gradle.kts"))) { - buildFile = new GradleKotlinProjectBuildFile(getProject(), platformDescriptor); + buildFile = new GradleKotlinProjectBuildFile(getProject(), catalog); } else if (Files.exists(rootProjectPath.resolve("settings.gradle")) && Files.exists(projectDirPath.resolve("build.gradle"))) { - buildFile = new GradleGroovyProjectBuildFile(getProject(), platformDescriptor); + buildFile = new GradleGroovyProjectBuildFile(getProject(), catalog); } else { throw new GradleException( "Mixed DSL is not supported. Both build and settings file need to use either Kotlin or Groovy DSL"); } - return QuarkusProject.of(getProject().getProjectDir().toPath(), platformDescriptor, buildFile); + return QuarkusProjectHelper.getProject(getProject().getProjectDir().toPath(), catalog, buildFile, log); + } + + protected GradleMessageWriter messageWriter() { + return new GradleMessageWriter(getProject().getLogger()); } protected static URL toURL(String url) { diff --git a/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusRemoveExtension.java b/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusRemoveExtension.java index 1adf369f5c4154..0d11fa2f81c670 100644 --- a/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusRemoveExtension.java +++ b/devtools/gradle/src/main/java/io/quarkus/gradle/tasks/QuarkusRemoveExtension.java @@ -39,7 +39,7 @@ public void removeExtension() { .map(String::trim) .collect(toSet()); try { - new RemoveExtensions(getQuarkusProject()) + new RemoveExtensions(getQuarkusProject(true)) .extensions(extensionsSet) .execute(); } catch (Exception e) { diff --git a/devtools/maven/pom.xml b/devtools/maven/pom.xml index 619bb19724c139..2f5aa084e1ed00 100644 --- a/devtools/maven/pom.xml +++ b/devtools/maven/pom.xml @@ -36,10 +36,6 @@ <groupId>io.quarkus</groupId> <artifactId>quarkus-platform-descriptor-json</artifactId> </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-platform-descriptor-resolver-json</artifactId> - </dependency> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-plugin-api</artifactId> diff --git a/devtools/maven/src/main/java/io/quarkus/maven/AddExtensionMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/AddExtensionMojo.java index 3a0a32b6c120a5..1983653ef206d6 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/AddExtensionMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/AddExtensionMojo.java @@ -2,10 +2,8 @@ import static java.util.stream.Collectors.toSet; -import java.net.URL; import java.util.Arrays; import java.util.HashSet; -import java.util.List; import java.util.Set; import org.apache.commons.lang3.StringUtils; @@ -17,7 +15,6 @@ import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; import io.quarkus.devtools.messagewriter.MessageWriter; import io.quarkus.devtools.project.QuarkusProject; -import io.quarkus.registry.DefaultExtensionRegistry; /** * Allow adding an extension to an existing pom.xml file. @@ -40,12 +37,6 @@ public class AddExtensionMojo extends QuarkusProjectMojoBase { @Parameter(property = "extension") String extension; - /** - * The URL where the registry is. - */ - @Parameter(property = "registry", alias = "quarkus.extension.registry") - List<URL> registries; - @Override protected void validateParameters() throws MojoExecutionException { if ((StringUtils.isBlank(extension) && (extensions == null || extensions.isEmpty())) // None are set @@ -69,9 +60,6 @@ public void doExecute(final QuarkusProject quarkusProject, final MessageWriter l try { AddExtensions addExtensions = new AddExtensions(quarkusProject) .extensions(ext.stream().map(String::trim).collect(toSet())); - if (registries != null && !registries.isEmpty()) { - addExtensions.extensionRegistry(DefaultExtensionRegistry.fromURLs(registries)); - } final QuarkusCommandOutcome outcome = addExtensions.execute(); if (!outcome.isSuccess()) { throw new MojoExecutionException("Unable to add extensions"); diff --git a/devtools/maven/src/main/java/io/quarkus/maven/CreateJBangMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/CreateJBangMojo.java index 05ecc15b89efe2..347346062a4551 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/CreateJBangMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/CreateJBangMojo.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Set; +import org.apache.commons.lang3.StringUtils; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Component; @@ -22,7 +23,12 @@ import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; import io.quarkus.devtools.commands.CreateJBangProject; import io.quarkus.devtools.commands.data.QuarkusCommandException; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.devtools.messagewriter.MessageWriter; +import io.quarkus.devtools.project.BuildTool; +import io.quarkus.devtools.project.QuarkusProject; +import io.quarkus.devtools.project.QuarkusProjectHelper; +import io.quarkus.platform.tools.maven.MojoMessageWriter; +import io.quarkus.registry.catalog.ExtensionCatalog; @Mojo(name = "create-jbang", requiresProject = false) public class CreateJBangMojo extends AbstractMojo { @@ -89,12 +95,17 @@ public void execute() throws MojoExecutionException { throw new MojoExecutionException("Failed to initialize Maven artifact resolver", e); } - final QuarkusPlatformDescriptor platform = CreateUtils.resolvePlatformDescriptor(bomGroupId, bomArtifactId, bomVersion, - mvn, getLog()); - - final CreateJBangProject createJBangProject = new CreateJBangProject(projectDirPath, platform) - .extensions(extensions) - .setValue("noJBangWrapper", noJBangWrapper); + final MessageWriter log = new MojoMessageWriter(getLog()); + final ExtensionCatalog catalog = CreateProjectMojo.resolveExtensionsCatalog( + StringUtils.defaultIfBlank(bomGroupId, null), + StringUtils.defaultIfBlank(bomArtifactId, null), + StringUtils.defaultIfBlank(bomVersion, null), + QuarkusProjectHelper.getCatalogResolver(mvn, log), mvn, log); + + final CreateJBangProject createJBangProject = new CreateJBangProject(QuarkusProject.of(projectDirPath, catalog, + QuarkusProjectHelper.getResourceLoader(catalog, mvn), log, BuildTool.MAVEN)) + .extensions(extensions) + .setValue("noJBangWrapper", noJBangWrapper); boolean success; diff --git a/devtools/maven/src/main/java/io/quarkus/maven/CreateProjectMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/CreateProjectMojo.java index 25d8ea61527eb3..048a886fba53d5 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/CreateProjectMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/CreateProjectMojo.java @@ -1,31 +1,21 @@ package io.quarkus.maven; import static org.fusesource.jansi.Ansi.ansi; -import static org.twdata.maven.mojoexecutor.MojoExecutor.artifactId; -import static org.twdata.maven.mojoexecutor.MojoExecutor.configuration; -import static org.twdata.maven.mojoexecutor.MojoExecutor.element; -import static org.twdata.maven.mojoexecutor.MojoExecutor.executeMojo; -import static org.twdata.maven.mojoexecutor.MojoExecutor.executionEnvironment; -import static org.twdata.maven.mojoexecutor.MojoExecutor.goal; -import static org.twdata.maven.mojoexecutor.MojoExecutor.groupId; -import static org.twdata.maven.mojoexecutor.MojoExecutor.name; -import static org.twdata.maven.mojoexecutor.MojoExecutor.plugin; -import static org.twdata.maven.mojoexecutor.MojoExecutor.version; +import java.io.BufferedWriter; import java.io.File; import java.io.IOException; +import java.io.StringWriter; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; -import java.util.Properties; import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; -import org.apache.maven.execution.DefaultMavenExecutionRequest; -import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Model; import org.apache.maven.model.Parent; @@ -35,10 +25,8 @@ import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.project.DefaultProjectBuildingRequest; import org.apache.maven.project.MavenProject; import org.apache.maven.project.ProjectBuilder; -import org.apache.maven.settings.Proxy; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.impl.RemoteRepositoryManager; @@ -47,13 +35,21 @@ import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; import io.quarkus.devtools.commands.CreateProject; +import io.quarkus.devtools.messagewriter.MessageWriter; import io.quarkus.devtools.project.BuildTool; +import io.quarkus.devtools.project.QuarkusProject; +import io.quarkus.devtools.project.QuarkusProjectHelper; import io.quarkus.devtools.project.codegen.SourceType; import io.quarkus.maven.components.MavenVersionEnforcer; import io.quarkus.maven.components.Prompter; import io.quarkus.maven.utilities.MojoUtils; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; import io.quarkus.platform.tools.ToolsUtils; +import io.quarkus.platform.tools.maven.MojoMessageWriter; +import io.quarkus.registry.ExtensionCatalogResolver; +import io.quarkus.registry.RegistryResolutionException; +import io.quarkus.registry.catalog.ExtensionCatalog; +import io.quarkus.registry.catalog.Platform; +import io.quarkus.registry.catalog.PlatformCatalog; /** * This goal helps in setting up Quarkus Maven project with quarkus-maven-plugin, with sensible defaults @@ -78,9 +74,6 @@ public class CreateProjectMojo extends AbstractMojo { @Parameter(property = "projectVersion") private String projectVersion; - @Parameter(property = "legacyCodegen", defaultValue = "false") - private boolean legacyCodegen; - /** * When true, do not include any example code in the generated Quarkus project. */ @@ -195,6 +188,15 @@ public class CreateProjectMojo extends AbstractMojo { @Override public void execute() throws MojoExecutionException { + // We detect the Maven version during the project generation to indicate the user immediately that the installed + // version may not be supported. + mavenVersionEnforcer.ensureMavenVersion(getLog(), session); + try { + Files.createDirectories(outputDirectory.toPath()); + } catch (IOException e) { + throw new MojoExecutionException("Could not create directory " + outputDirectory, e); + } + final MavenArtifactResolver mvn; try { mvn = MavenArtifactResolver.builder() @@ -206,17 +208,14 @@ public void execute() throws MojoExecutionException { } catch (Exception e) { throw new MojoExecutionException("Failed to initialize Maven artifact resolver", e); } - final QuarkusPlatformDescriptor platform = CreateUtils.resolvePlatformDescriptor(bomGroupId, bomArtifactId, bomVersion, - mvn, getLog()); + final MojoMessageWriter log = new MojoMessageWriter(getLog()); + final ExtensionCatalogResolver catalogResolver = QuarkusProjectHelper.getCatalogResolver(mvn, log); - // We detect the Maven version during the project generation to indicate the user immediately that the installed - // version may not be supported. - mavenVersionEnforcer.ensureMavenVersion(getLog(), session); - try { - Files.createDirectories(outputDirectory.toPath()); - } catch (IOException e) { - throw new MojoExecutionException("Could not create directory " + outputDirectory, e); - } + final ExtensionCatalog catalog = resolveExtensionsCatalog( + StringUtils.defaultIfBlank(bomGroupId, null), + StringUtils.defaultIfBlank(bomArtifactId, null), + StringUtils.defaultIfBlank(bomVersion, null), + catalogResolver, mvn, log); File projectRoot = outputDirectory; File pom = project != null ? project.getFile() : null; @@ -272,8 +271,9 @@ public void execute() throws MojoExecutionException { final SourceType sourceType = CreateProject.determineSourceType(extensions); sanitizeOptions(sourceType); - final CreateProject createProject = new CreateProject(projectDirPath, platform) - .buildTool(buildToolEnum) + QuarkusProject newProject = QuarkusProject.of(projectDirPath, catalog, + QuarkusProjectHelper.getResourceLoader(catalog, mvn), log, buildToolEnum); + final CreateProject createProject = new CreateProject(newProject) .groupId(projectGroupId) .artifactId(projectArtifactId) .version(projectVersion) @@ -282,7 +282,6 @@ public void execute() throws MojoExecutionException { .packageName(packageName) .extensions(extensions) .overrideExamples(examples) - .legacyCodegen(legacyCodegen) .noExamples(noExamples); if (path != null) { createProject.setValue("path", path); @@ -304,14 +303,6 @@ public void execute() throws MojoExecutionException { MojoUtils.write(parentPomModel, pom); MojoUtils.write(subModulePomModel, subModulePomFile); } - if (legacyCodegen) { - File createdDependenciesBuildFile = new File(projectRoot, buildToolEnum.getDependenciesFile()); - if (BuildTool.MAVEN.equals(buildToolEnum)) { - createMavenWrapper(createdDependenciesBuildFile, ToolsUtils.readQuarkusProperties(platform)); - } else if (BuildTool.GRADLE.equals(buildToolEnum) || BuildTool.GRADLE_KOTLIN_DSL.equals(buildToolEnum)) { - createGradleWrapper(platform, projectDirPath); - } - } } catch (Exception e) { throw new MojoExecutionException("Failed to generate Quarkus project", e); } @@ -323,80 +314,70 @@ public void execute() throws MojoExecutionException { } } - private void createGradleWrapper(QuarkusPlatformDescriptor platform, Path projectDirPath) { - try { - Files.createDirectories(projectDirPath.resolve("gradle/wrapper")); - - for (String filename : CreateUtils.GRADLE_WRAPPER_FILES) { - byte[] fileContent = platform.loadResource(CreateUtils.GRADLE_WRAPPER_PATH + '/' + filename, - is -> { - byte[] buffer = new byte[is.available()]; - is.read(buffer); - return buffer; - }); - final Path destination = projectDirPath.resolve(filename); - Files.write(destination, fileContent); - } - - projectDirPath.resolve("gradlew").toFile().setExecutable(true); - projectDirPath.resolve("gradlew.bat").toFile().setExecutable(true); - } catch (IOException e) { - getLog().error("Unable to copy Gradle wrapper from platform descriptor", e); + static ExtensionCatalog resolveExtensionsCatalog(String groupId, String artifactId, String version, + ExtensionCatalogResolver catalogResolver, MavenArtifactResolver artifactResolver, MessageWriter log) + throws MojoExecutionException { + + if (!catalogResolver.hasRegistries()) { + // TODO: this should normally result in an error, however for the time being + // until we get the registry service up and running this will allow + // a fall back to the legacy way of resolving the default platform catalog directly + return ToolsUtils.resolvePlatformDescriptorDirectly(groupId, artifactId, + version == null ? CreateUtils.resolvePluginInfo(CreateUtils.class).getVersion() : version, artifactResolver, + log); } - } - private void createMavenWrapper(File createdPomFile, Properties props) { try { - // we need to modify the maven environment used by the wrapper plugin since the project could have been - // created in a directory other than the current - MavenProject newProject = projectBuilder.build( - createdPomFile, new DefaultProjectBuildingRequest(session.getProjectBuildingRequest())).getProject(); - - MavenExecutionRequest newExecutionRequest = DefaultMavenExecutionRequest.copy(session.getRequest()); - newExecutionRequest.setBaseDirectory(createdPomFile.getParentFile()); - - MavenSession newSession = new MavenSession(session.getContainer(), session.getRepositorySession(), - newExecutionRequest, session.getResult()); - newSession.setCurrentProject(newProject); - - setProxySystemPropertiesFromSession(); - - executeMojo( - plugin( - groupId("io.takari"), - artifactId("maven"), - version(ToolsUtils.getMavenWrapperVersion(props))), - goal("wrapper"), - configuration( - element(name("maven"), ToolsUtils.getProposedMavenVersion(props))), - executionEnvironment( - newProject, - newSession, - pluginManager)); - } catch (Exception e) { - // no reason to fail if the wrapper could not be created - getLog().error("Unable to install the Maven wrapper (./mvnw) in the project", e); - } - } - - private void setProxySystemPropertiesFromSession() { - List<Proxy> proxiesFromSession = session.getRequest().getProxies(); - // - takari maven uses https to download the maven wrapper - // - don't do anything if proxy system property is already set - if (!proxiesFromSession.isEmpty() && System.getProperty("https.proxyHost") == null) { - - // use the first active proxy for setting the system properties - proxiesFromSession.stream() - .filter(Proxy::isActive) - .findFirst() - .ifPresent(proxy -> { - // note: a http proxy _is_ usable as https.proxyHost - System.setProperty("https.proxyHost", proxy.getHost()); - System.setProperty("https.proxyPort", String.valueOf(proxy.getPort())); - if (proxy.getNonProxyHosts() != null) { - System.setProperty("http.nonProxyHosts", proxy.getNonProxyHosts()); - } - }); + if (groupId == null && artifactId == null && version == null) { + return catalogResolver.resolveExtensionCatalog(); + } + final PlatformCatalog platformsCatalog = catalogResolver.resolvePlatformCatalog(); + if (platformsCatalog == null) { + throw new MojoExecutionException( + "No platforms are available. Please make sure your .quarkus/config.yaml configuration includes proper extensions registry configuration"); + } + ArtifactCoords matchedBom = null; + List<ArtifactCoords> matchedBoms = null; + for (Platform p : platformsCatalog.getPlatforms()) { + final ArtifactCoords bom = p.getBom(); + if (version != null && !bom.getVersion().equals(version)) { + continue; + } + if (artifactId != null && !bom.getArtifactId().equals(artifactId)) { + continue; + } + if (groupId != null && !bom.getGroupId().equals(groupId)) { + continue; + } + if (matchedBom != null) { + if (matchedBoms == null) { + matchedBoms = new ArrayList<>(); + matchedBoms.add(matchedBom); + } + matchedBoms.add(bom); + } else { + matchedBom = bom; + } + } + if (matchedBoms != null) { + StringWriter buf = new StringWriter(); + buf.append("Multiple platforms were matching the requested platform BOM coordinates "); + buf.append(groupId == null ? "*" : groupId).append(':'); + buf.append(artifactId == null ? "*" : artifactId).append(':'); + buf.append(version == null ? "*" : version).append(": "); + try (BufferedWriter writer = new BufferedWriter(buf)) { + for (ArtifactCoords bom : matchedBoms) { + writer.newLine(); + writer.append("- ").append(bom.toString()); + } + } catch (IOException e) { + // + } + throw new MojoExecutionException(buf.toString()); + } + return catalogResolver.resolveExtensionCatalog(Arrays.asList(matchedBom)); + } catch (RegistryResolutionException e) { + throw new MojoExecutionException("Failed to resolve the extensions catalog", e); } } @@ -434,38 +415,18 @@ private void askTheUserForMissingValues() throws MojoExecutionException { DEFAULT_VERSION); } - if (legacyCodegen) { - if (StringUtils.isBlank(className)) { - // Ask the user if he want to create a resource - String answer = prompter.promptWithDefaultValue("Do you want to create a REST resource? (y/n)", "no"); - if (isTrueOrYes(answer)) { - String defaultResourceName = projectGroupId.replace("-", ".") - .replace("_", ".") + ".HelloResource"; - className = prompter.promptWithDefaultValue("Set the resource classname", defaultResourceName); - if (StringUtils.isBlank(path)) { - path = prompter.promptWithDefaultValue("Set the resource path ", - CreateUtils.getDerivedPath(className)); - } - } else { - className = null; - path = null; - } - } - } else { - if (examples.isEmpty()) { - if (extensions.isEmpty()) { - extensions = Arrays - .stream(prompter - .promptWithDefaultValue("What extensions do you wish to add (comma separated list)", - DEFAULT_EXTENSIONS) - .split(",")) - .map(String::trim).filter(StringUtils::isNotEmpty) - .collect(Collectors.toSet()); - } - String answer = prompter.promptWithDefaultValue( - "Do you want example code to get started (yes), or just an empty project (no)", "yes"); - noExamples = answer.startsWith("n"); + if (examples.isEmpty()) { + if (extensions.isEmpty()) { + extensions = Arrays + .stream(prompter + .promptWithDefaultValue("What extensions do you wish to add (comma separated list)", + DEFAULT_EXTENSIONS) + .split(",")) + .map(String::trim).filter(StringUtils::isNotEmpty).collect(Collectors.toSet()); } + String answer = prompter.promptWithDefaultValue( + "Do you want example code to get started (yes), or just an empty project (no)", "yes"); + noExamples = answer.startsWith("n"); } } catch (IOException e) { throw new MojoExecutionException("Unable to get user input", e); @@ -478,14 +439,6 @@ private boolean shouldUseDefaults() { } - private boolean isTrueOrYes(String answer) { - if (answer == null) { - return false; - } - String content = answer.trim().toLowerCase(); - return "true".equalsIgnoreCase(content) || "yes".equalsIgnoreCase(content) || "y".equalsIgnoreCase(content); - } - private void sanitizeOptions(SourceType sourceType) { if (className != null) { className = sourceType.stripExtensionFrom(className); @@ -529,5 +482,4 @@ private void printUserInstructions(File root) { getLog().info("========================================================================================"); getLog().info(""); } - } diff --git a/devtools/maven/src/main/java/io/quarkus/maven/CreateUtils.java b/devtools/maven/src/main/java/io/quarkus/maven/CreateUtils.java index e1d207ef041236..1b5b8896cc3d22 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/CreateUtils.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/CreateUtils.java @@ -9,28 +9,20 @@ import javax.xml.parsers.DocumentBuilderFactory; import org.apache.commons.lang3.StringUtils; -import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.apache.maven.model.Plugin; import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.logging.Log; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver; -import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; import io.quarkus.bootstrap.util.ZipUtils; import io.quarkus.maven.utilities.MojoUtils; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.descriptor.resolver.json.QuarkusJsonPlatformDescriptorResolver; -import io.quarkus.platform.tools.config.QuarkusPlatformConfig; -import io.quarkus.platform.tools.maven.MojoMessageWriter; public final class CreateUtils { public static final String DEFAULT_PLATFORM_BOM_GROUP_ID = "io.quarkus"; public static final String QUARKUS_CORE_BOM_ARTIFACT_ID = "quarkus-bom"; - public static final String DEFAULT_PLATFORM_BOM_ARTIFACT_ID = QUARKUS_CORE_BOM_ARTIFACT_ID; + public static final String DEFAULT_PLATFORM_BOM_ARTIFACT_ID = "quarkus-universe-bom"; public static final String GRADLE_WRAPPER_PATH = "gradle-wrapper"; public static final String[] GRADLE_WRAPPER_FILES = new String[] { @@ -44,66 +36,6 @@ private CreateUtils() { //Not to be constructed } - private static boolean isVersionRange(String versionStr) { - if (versionStr == null || versionStr.isEmpty()) { - return false; - } - char c = versionStr.charAt(0); - if (c == '[' || c == '(') { - return true; - } - c = versionStr.charAt(versionStr.length() - 1); - if (c == ']' || c == ')') { - return true; - } - return versionStr.indexOf(',') >= 0; - } - - static QuarkusPlatformDescriptor setGlobalPlatformDescriptor(final String bomGroupId, final String bomArtifactId, - final String bomVersion, - MavenArtifactResolver mvn, Log log) throws MojoExecutionException { - final QuarkusPlatformDescriptor platform = resolvePlatformDescriptor(bomGroupId, bomArtifactId, bomVersion, mvn, log); - QuarkusPlatformConfig.defaultConfigBuilder().setPlatformDescriptor(platform).build(); - return platform; - } - - static QuarkusPlatformDescriptor resolvePlatformDescriptor(final String bomGroupId, final String bomArtifactId, - final String bomVersion, MavenArtifactResolver mvn, Log log) throws MojoExecutionException { - final QuarkusJsonPlatformDescriptorResolver platformResolver = QuarkusJsonPlatformDescriptorResolver.newInstance() - .setMessageWriter(new MojoMessageWriter(log)) - .setArtifactResolver(new BootstrapAppModelResolver(mvn)); - - String groupId = StringUtils.defaultIfBlank(bomGroupId, null); - String artifactId = StringUtils.defaultIfBlank(bomArtifactId, null); - String version = StringUtils.defaultIfBlank(bomVersion, null); - - if (version == null) { - if (CreateUtils.QUARKUS_CORE_BOM_ARTIFACT_ID.equals(artifactId)) { - version = resolvePluginInfo(CreateUtils.class).getVersion(); - } else if ((groupId == null && artifactId == null) || ("quarkus-universe-bom".equals(artifactId))) { - String baseVersion = resolvePluginInfo(CreateUtils.class).getVersion(); - DefaultArtifactVersion pluginVersion = new DefaultArtifactVersion(baseVersion); - int majorVer = pluginVersion.getMajorVersion(); - int minorVer = pluginVersion.getMinorVersion(); - version = "[" + majorVer + "." + minorVer + "-alpha, " + majorVer + "." + (minorVer + 1) + "-alpha)"; - } - } - - final QuarkusPlatformDescriptor platform; - if (version == null) { - if (artifactId == null && groupId == null) { - platform = platformResolver.resolve(); - } else { - platform = platformResolver.resolveLatestFromBom(groupId, artifactId, null); - } - } else if (isVersionRange(version)) { - platform = platformResolver.resolveLatestFromBom(groupId, artifactId, version); - } else { - platform = platformResolver.resolveFromBom(groupId, artifactId, version); - } - return platform; - } - public static String getDerivedPath(String className) { String[] resourceClassName = StringUtils.splitByCharacterTypeCamelCase( className.substring(className.lastIndexOf(".") + 1)); diff --git a/devtools/maven/src/main/java/io/quarkus/maven/ListExtensionsMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/ListExtensionsMojo.java index 7d3bc1a7726642..8ab5df047dc3c7 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/ListExtensionsMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/ListExtensionsMojo.java @@ -1,8 +1,5 @@ package io.quarkus.maven; -import java.net.URL; -import java.util.List; - import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; @@ -10,7 +7,6 @@ import io.quarkus.devtools.commands.ListExtensions; import io.quarkus.devtools.messagewriter.MessageWriter; import io.quarkus.devtools.project.QuarkusProject; -import io.quarkus.registry.DefaultExtensionRegistry; /** * List the available extensions. @@ -46,12 +42,6 @@ public class ListExtensionsMojo extends QuarkusProjectMojoBase { @Parameter(property = "installed", defaultValue = "false") protected boolean installed; - /** - * The extension registry URLs - */ - @Parameter(property = "registry", alias = "quarkus.extension.registry") - List<URL> registries; - @Override public void doExecute(final QuarkusProject quarkusProject, final MessageWriter log) throws MojoExecutionException { try { @@ -60,9 +50,6 @@ public void doExecute(final QuarkusProject quarkusProject, final MessageWriter l .format(format) .search(searchPattern) .installed(installed); - if (registries != null && !registries.isEmpty()) { - listExtensions.extensionRegistry(DefaultExtensionRegistry.fromURLs(registries)); - } listExtensions.execute(); } catch (Exception e) { throw new MojoExecutionException("Failed to list extensions", e); diff --git a/devtools/maven/src/main/java/io/quarkus/maven/ListPlatformsMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/ListPlatformsMojo.java new file mode 100644 index 00000000000000..8a75f1bcc1a75a --- /dev/null +++ b/devtools/maven/src/main/java/io/quarkus/maven/ListPlatformsMojo.java @@ -0,0 +1,43 @@ +package io.quarkus.maven; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; + +import io.quarkus.devtools.commands.ListPlatforms; +import io.quarkus.devtools.messagewriter.MessageWriter; +import io.quarkus.devtools.project.QuarkusProject; +import io.quarkus.registry.Constants; + +/** + * List imported and optionally other platforms available for the project. + */ +@Mojo(name = "list-platforms", requiresProject = false) +public class ListPlatformsMojo extends QuarkusProjectMojoBase { + + /** + * List the already installed extensions + */ + @Parameter(property = "installed", defaultValue = "false") + protected boolean installed; + + @Override + public void doExecute(final QuarkusProject quarkusProject, final MessageWriter log) throws MojoExecutionException { + if (installed) { + getImportedPlatforms().forEach(coords -> { + final StringBuilder buf = new StringBuilder(); + buf.append(coords.getGroupId()).append(":") + .append(coords.getArtifactId().substring(0, + coords.getArtifactId().length() - Constants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX.length())) + .append("::pom:").append(coords.getVersion()); + log.info(buf.toString()); + }); + return; + } + try { + new ListPlatforms(quarkusProject).execute(); + } catch (Exception e) { + throw new MojoExecutionException("Failed to list platforms", e); + } + } +} diff --git a/devtools/maven/src/main/java/io/quarkus/maven/ListUpdatesMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/ListUpdatesMojo.java new file mode 100644 index 00000000000000..eee1e9f479c496 --- /dev/null +++ b/devtools/maven/src/main/java/io/quarkus/maven/ListUpdatesMojo.java @@ -0,0 +1,93 @@ +package io.quarkus.maven; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; + +import io.quarkus.devtools.messagewriter.MessageWriter; +import io.quarkus.devtools.project.QuarkusProject; +import io.quarkus.registry.Constants; +import io.quarkus.registry.RegistryResolutionException; +import io.quarkus.registry.catalog.Platform; +import io.quarkus.registry.catalog.PlatformCatalog; + +/** + * List updates available for the project + */ +@Mojo(name = "list-updates", requiresProject = false) +public class ListUpdatesMojo extends QuarkusProjectMojoBase { + + /** + * List the already installed extensions + */ + @Parameter(property = "installed", defaultValue = "false") + protected boolean installed; + + @Override + public void doExecute(final QuarkusProject quarkusProject, final MessageWriter log) throws MojoExecutionException { + + final PlatformCatalog catalog; + try { + catalog = getExtensionCatalogResolver().resolvePlatformCatalog(); + } catch (RegistryResolutionException e) { + throw new MojoExecutionException("Failed to resolve the Quarkus platform catalog", e); + } + final List<Platform> platforms = catalog == null ? Collections.emptyList() : catalog.getPlatforms(); + if (platforms.isEmpty()) { + return; + } + List<ArtifactCoords> latestList = new ArrayList<>(platforms.size()); + for (Platform p : platforms) { + final ArtifactCoords bom = p.getBom(); + latestList.add(bom); + } + + final List<ArtifactCoords> platformJsons = getImportedPlatforms(); + final List<ArtifactCoords> importedPlatformBoms = new ArrayList<>(platformJsons.size()); + for (ArtifactCoords descriptor : platformJsons) { + final ArtifactCoords importedBom = new ArtifactCoords(descriptor.getGroupId(), + descriptor.getArtifactId().substring(0, + descriptor.getArtifactId().length() - Constants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX.length()), + null, "pom", descriptor.getVersion()); + if (!latestList.remove(importedBom)) { + importedPlatformBoms.add(importedBom); + } + } + + final Map<ArtifactKey, String> latest = new HashMap<>(platforms.size()); + for (ArtifactCoords latestBom : latestList) { + latest.put(latestBom.getKey(), latestBom.getVersion()); + } + + log.info("Available Quarkus platform updates:"); + final StringBuilder buf = new StringBuilder(0); + for (ArtifactCoords importedBom : importedPlatformBoms) { + final ArtifactKey key = importedBom.getKey(); + final String update = latest.get(key); + if (update == null || importedBom.getVersion().equals(update)) { + continue; + } + buf.setLength(0); + buf.append(key.getGroupId()).append(':').append(key.getArtifactId()); + for (int i = buf.length(); i < 45; ++i) { + buf.append(' '); + } + buf.append(importedBom.getVersion()); + for (int i = buf.length(); i < 60; ++i) { + buf.append(' '); + } + buf.append(" -> ").append(update); + log.info(buf.toString()); + } + + if (buf.length() == 0) { + log.info("No updates yet, ping @gsmet"); + } + } +} diff --git a/devtools/maven/src/main/java/io/quarkus/maven/MavenProjectBuildFile.java b/devtools/maven/src/main/java/io/quarkus/maven/MavenProjectBuildFile.java index 8fbf8b6aaa18e0..baa4d52148c5d0 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/MavenProjectBuildFile.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/MavenProjectBuildFile.java @@ -23,7 +23,7 @@ import io.quarkus.devtools.project.BuildTool; import io.quarkus.devtools.project.buildfile.BuildFile; import io.quarkus.maven.utilities.MojoUtils; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.registry.catalog.ExtensionCatalog; public class MavenProjectBuildFile extends BuildFile { @@ -37,11 +37,11 @@ public class MavenProjectBuildFile extends BuildFile { protected List<AppArtifactCoords> managedDependencies; protected Model model; - public MavenProjectBuildFile(Path projectDirPath, QuarkusPlatformDescriptor platformDescriptor, Supplier<Model> model, + public MavenProjectBuildFile(Path projectDirPath, ExtensionCatalog extensionsCatalog, Supplier<Model> model, Supplier<List<org.eclipse.aether.graph.Dependency>> projectDeps, Supplier<List<org.eclipse.aether.graph.Dependency>> projectManagedDeps, Properties projectProps) { - super(projectDirPath, platformDescriptor); + super(projectDirPath, extensionsCatalog); this.modelSupplier = model; this.projectDepsSupplier = projectDeps; this.projectManagedDepsSupplier = projectManagedDeps; diff --git a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusProjectMojoBase.java b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusProjectMojoBase.java index 9b451fc6c573bf..e0dcbcd077aff0 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusProjectMojoBase.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusProjectMojoBase.java @@ -1,6 +1,8 @@ package io.quarkus.maven; +import java.io.BufferedWriter; import java.io.IOException; +import java.io.StringWriter; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -8,9 +10,6 @@ import java.util.List; import org.apache.maven.model.Dependency; -import org.apache.maven.model.DependencyManagement; -import org.apache.maven.model.Model; -import org.apache.maven.model.Parent; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Component; @@ -25,21 +24,22 @@ import org.eclipse.aether.impl.RemoteRepositoryManager; import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.resolution.ArtifactDescriptorResult; -import org.eclipse.aether.resolution.ArtifactResult; import io.quarkus.bootstrap.BootstrapConstants; -import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; -import io.quarkus.bootstrap.resolver.maven.workspace.ModelUtils; import io.quarkus.devtools.messagewriter.MessageWriter; import io.quarkus.devtools.project.BuildTool; import io.quarkus.devtools.project.QuarkusProject; -import io.quarkus.platform.descriptor.CombinedQuarkusPlatformDescriptor; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.descriptor.resolver.json.QuarkusJsonPlatformDescriptorResolver; +import io.quarkus.devtools.project.QuarkusProjectHelper; +import io.quarkus.platform.descriptor.loader.json.ClassPathResourceLoader; import io.quarkus.platform.tools.ToolsConstants; +import io.quarkus.platform.tools.ToolsUtils; import io.quarkus.platform.tools.maven.MojoMessageWriter; +import io.quarkus.registry.ExtensionCatalogResolver; +import io.quarkus.registry.RegistryResolutionException; +import io.quarkus.registry.catalog.ExtensionCatalog; +import io.quarkus.registry.catalog.Platform; public abstract class QuarkusProjectMojoBase extends AbstractMojo { @@ -55,7 +55,7 @@ public abstract class QuarkusProjectMojoBase extends AbstractMojo { @Parameter(defaultValue = "${project.remoteProjectRepositories}", readonly = true, required = true) protected List<RemoteRepository> repos; - @Parameter(property = "bomGroupId", defaultValue = ToolsConstants.DEFAULT_PLATFORM_BOM_GROUP_ID) + @Parameter(property = "bomGroupId", required = false) private String bomGroupId; @Parameter(property = "bomArtifactId", required = false) @@ -67,9 +67,13 @@ public abstract class QuarkusProjectMojoBase extends AbstractMojo { @Component RemoteRepositoryManager remoteRepositoryManager; + private List<ArtifactCoords> importedPlatforms; + private Artifact projectArtifact; private ArtifactDescriptorResult projectDescr; private MavenArtifactResolver artifactResolver; + private ExtensionCatalogResolver catalogResolver; + private MessageWriter log; @Override public void execute() throws MojoExecutionException { @@ -77,7 +81,6 @@ public void execute() throws MojoExecutionException { // Validate Mojo parameters validateParameters(); - final MessageWriter log = new MojoMessageWriter(getLog()); final Path projectDirPath = baseDir(); BuildTool buildTool = QuarkusProject.resolveExistingProjectBuildTool(projectDirPath); if (buildTool == null) { @@ -85,11 +88,13 @@ public void execute() throws MojoExecutionException { buildTool = BuildTool.MAVEN; } - final QuarkusPlatformDescriptor platformDescriptor = resolvePlatformDescriptor(log); + final ExtensionCatalog catalog = resolveExtensionsCatalog(); + final ClassPathResourceLoader codestartsResourceLoader = QuarkusProjectHelper.getResourceLoader(catalog, + artifactResolver()); final QuarkusProject quarkusProject; if (BuildTool.MAVEN.equals(buildTool) && project.getFile() != null) { - quarkusProject = QuarkusProject.of(baseDir(), platformDescriptor, - new MavenProjectBuildFile(baseDir(), platformDescriptor, () -> project.getOriginalModel(), + quarkusProject = QuarkusProject.of(baseDir(), catalog, codestartsResourceLoader, getMessageWriter(), + new MavenProjectBuildFile(baseDir(), catalog, () -> project.getOriginalModel(), () -> { try { return projectDependencies(); @@ -106,10 +111,14 @@ public void execute() throws MojoExecutionException { }, project.getModel().getProperties())); } else { - quarkusProject = QuarkusProject.of(baseDir(), platformDescriptor, buildTool); + quarkusProject = QuarkusProject.of(baseDir(), catalog, codestartsResourceLoader, log, buildTool); } - doExecute(quarkusProject, log); + doExecute(quarkusProject, getMessageWriter()); + } + + protected MessageWriter getMessageWriter() { + return log == null ? log = new MojoMessageWriter(getLog()) : log; } private ArtifactDescriptorResult projectDescriptor() throws MojoExecutionException { @@ -128,146 +137,133 @@ protected Path baseDir() { : project.getBasedir().toPath(); } - private QuarkusPlatformDescriptor resolvePlatformDescriptor(final MessageWriter log) throws MojoExecutionException { - // Resolve and setup the platform descriptor - try { - final MavenArtifactResolver mvn = artifactResolver(); - if (project.getFile() != null) { - List<Artifact> descrArtifactList = collectQuarkusPlatformDescriptors(log, mvn); - if (descrArtifactList.isEmpty()) { - descrArtifactList = resolveLegacyQuarkusPlatformDescriptors(log, mvn); - } - if (!descrArtifactList.isEmpty()) { - final QuarkusJsonPlatformDescriptorResolver descriptorResolver = QuarkusJsonPlatformDescriptorResolver - .newInstance() - .setArtifactResolver(new BootstrapAppModelResolver(mvn)) - .setMessageWriter(log); - - if (descrArtifactList.size() == 1) { - return descriptorResolver.resolveFromJson(descrArtifactList.get(0).getFile().toPath()); - } + protected boolean isLimitExtensionsToImportedPlatforms() { + return false; + } - // Typically, quarkus-bom platform will appear first. - // The descriptors that are generated today are not fragmented and include everything - // a platform offers. Which means if the quarkus-bom platform appears first and its version - // matches the Quarkus core version of the platform built on top of the quarkus-bom - // (e.g. quarkus-universe-bom) the quarkus-bom platform can be skipped, - // since it will already be included in the platform that's built on top of it - int i = 0; - Artifact platformArtifact = descrArtifactList.get(0); - final String quarkusBomPlatformArtifactId = "quarkus-bom" - + BootstrapConstants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX; - Artifact quarkusBomPlatformArtifact = null; - if (quarkusBomPlatformArtifactId.equals(platformArtifact.getArtifactId())) { - quarkusBomPlatformArtifact = platformArtifact; - } - final CombinedQuarkusPlatformDescriptor.Builder builder = CombinedQuarkusPlatformDescriptor.builder(); - while (++i < descrArtifactList.size()) { - platformArtifact = descrArtifactList.get(i); - final QuarkusPlatformDescriptor descriptor = descriptorResolver - .resolveFromJson(platformArtifact.getFile().toPath()); - if (quarkusBomPlatformArtifact != null) { - if (!quarkusBomPlatformArtifact.getVersion().equals(descriptor.getQuarkusVersion())) { - builder.addPlatform( - descriptorResolver.resolveFromJson(quarkusBomPlatformArtifact.getFile().toPath())); + private ExtensionCatalog resolveExtensionsCatalog() throws MojoExecutionException { + final ExtensionCatalogResolver catalogResolver = getExtensionCatalogResolver(); + if (catalogResolver.hasRegistries()) { + try { + return isLimitExtensionsToImportedPlatforms() + ? catalogResolver.resolveExtensionCatalog(getImportedPlatforms()) + : catalogResolver.resolveExtensionCatalog(getQuarkusCoreVersion()); + } catch (Exception e) { + throw new MojoExecutionException("Failed to resolve the Quarkus extensions catalog", e); + } + } + return ToolsUtils.mergePlatforms(collectImportedPlatforms(), artifactResolver()); + } + + protected ExtensionCatalogResolver getExtensionCatalogResolver() throws MojoExecutionException { + return catalogResolver == null + ? catalogResolver = QuarkusProjectHelper.getCatalogResolver(artifactResolver(), getMessageWriter()) + : catalogResolver; + } + + protected List<ArtifactCoords> getImportedPlatforms() throws MojoExecutionException { + if (importedPlatforms == null) { + if (project.getFile() == null) { + if (bomGroupId == null && bomArtifactId == null && bomVersion == null) { + return Collections.emptyList(); + } + if (bomGroupId == null) { + bomGroupId = ToolsConstants.DEFAULT_PLATFORM_BOM_GROUP_ID; + } + final ExtensionCatalogResolver catalogResolver = getExtensionCatalogResolver(); + ArtifactCoords platformBom = null; + List<ArtifactCoords> matches = null; + try { + for (Platform p : catalogResolver.resolvePlatformCatalog().getPlatforms()) { + final ArtifactCoords bom = p.getBom(); + if (bomGroupId != null && !bom.getGroupId().equals(bomGroupId)) { + continue; + } + if (bomArtifactId != null && !bom.getArtifactId().equals(bomArtifactId)) { + continue; + } + if (bomVersion != null && !bom.getVersion().equals(bomVersion)) { + continue; + } + if (platformBom == null) { + platformBom = bom; + } else { + if (matches == null) { + matches = new ArrayList<>(); + matches.add(platformBom); } - quarkusBomPlatformArtifact = null; + matches.add(bom); } - builder.addPlatform(descriptorResolver.resolveFromJson(platformArtifact.getFile().toPath())); } - return builder.build(); + } catch (RegistryResolutionException e) { + throw new MojoExecutionException("Failed to resolve the catalog of Quarkus platforms", e); } + if (matches != null) { + final StringWriter buf = new StringWriter(); + buf.append("Found multiple platforms matching the provided arguments: "); + try (BufferedWriter writer = new BufferedWriter(buf)) { + for (ArtifactCoords coords : matches) { + writer.newLine(); + writer.append("- ").append(coords.toString()); + } + } catch (IOException e) { + buf.append(matches.toString()); + } + throw new MojoExecutionException(buf.toString()); + } + return importedPlatforms = Collections.singletonList(platformBom); } - return CreateUtils.resolvePlatformDescriptor(bomGroupId, bomArtifactId, bomVersion, mvn, getLog()); - } catch (Exception e) { - throw new MojoExecutionException("Failed to initialize maven artifact resolver", e); + importedPlatforms = collectImportedPlatforms(); } + return importedPlatforms; } - private MavenArtifactResolver artifactResolver() throws BootstrapMavenException { + private MavenArtifactResolver artifactResolver() throws MojoExecutionException { if (artifactResolver == null) { - artifactResolver = MavenArtifactResolver.builder() - .setRepositorySystem(repoSystem) - .setRepositorySystemSession(repoSession) - .setRemoteRepositories(repos) - .setRemoteRepositoryManager(remoteRepositoryManager) - .build(); - } - return artifactResolver; - } - - private List<Artifact> resolveLegacyQuarkusPlatformDescriptors(MessageWriter log, MavenArtifactResolver mvn) - throws IOException { - final List<Artifact> descrArtifactList = new ArrayList<>(2); - for (Dependency dep : getManagedDependencies(mvn)) { - if ((dep.getScope() == null || !dep.getScope().equals("import")) - && (dep.getType() == null || !dep.getType().equals("pom"))) { - continue; - } - // We don't know which BOM is the platform one, so we are trying every BOM here - final String bomVersion = resolveValue(dep.getVersion()); - final String bomGroupId = resolveValue(dep.getGroupId()); - final String bomArtifactId = resolveValue(dep.getArtifactId()); - if (bomVersion == null || bomGroupId == null || bomArtifactId == null) { - continue; - } - - final Artifact jsonArtifact = resolveJsonOrNull(mvn, bomGroupId, bomArtifactId, bomVersion); - if (jsonArtifact != null) { - log.debug("Found legacy platform %s", jsonArtifact); - descrArtifactList.add(jsonArtifact); + try { + artifactResolver = MavenArtifactResolver.builder() + .setRepositorySystem(repoSystem) + .setRepositorySystemSession(repoSession) + .setRemoteRepositories(repos) + .setRemoteRepositoryManager(remoteRepositoryManager) + .build(); + } catch (BootstrapMavenException e) { + throw new MojoExecutionException("Failed to initialize Maven artifact resolver", e); } } - return descrArtifactList; + return artifactResolver; } - private List<Artifact> collectQuarkusPlatformDescriptors(MessageWriter log, MavenArtifactResolver mvn) + private List<ArtifactCoords> collectImportedPlatforms() throws MojoExecutionException { - final List<Artifact> descrArtifactList = new ArrayList<>(2); + final List<ArtifactCoords> descriptors = new ArrayList<>(4); final List<Dependency> constraints = project.getDependencyManagement() == null ? Collections.emptyList() : project.getDependencyManagement().getDependencies(); if (!constraints.isEmpty()) { + final MessageWriter log = getMessageWriter(); for (Dependency d : constraints) { if (!("json".equals(d.getType()) && d.getArtifactId().endsWith(BootstrapConstants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX))) { continue; } - final Artifact a = new DefaultArtifact(d.getGroupId(), d.getArtifactId(), d.getClassifier(), + final ArtifactCoords a = new ArtifactCoords(d.getGroupId(), d.getArtifactId(), d.getClassifier(), d.getType(), d.getVersion()); - try { - log.debug("Found platform descriptor %s", a); - descrArtifactList.add(mvn.resolve(a).getArtifact()); - } catch (Exception e) { - throw new MojoExecutionException("Failed to resolve the platform descriptor " + a, e); - } + descriptors.add(a); + log.debug("Found platform descriptor %s", a); } } - return descrArtifactList; + return descriptors; } - private Artifact resolveJsonOrNull(MavenArtifactResolver mvn, String bomGroupId, String bomArtifactId, String bomVersion) { - Artifact jsonArtifact = new DefaultArtifact(bomGroupId, bomArtifactId, null, "json", bomVersion); - try { - jsonArtifact = mvn.resolve(jsonArtifact).getArtifact(); - } catch (Exception e) { - if (getLog().isDebugEnabled()) { - getLog().debug("Failed to resolve JSON descriptor as " + jsonArtifact); - } - jsonArtifact = new DefaultArtifact(bomGroupId, bomArtifactId + "-descriptor-json", null, "json", - bomVersion); - try { - jsonArtifact = mvn.resolve(jsonArtifact).getArtifact(); - } catch (Exception e1) { - if (getLog().isDebugEnabled()) { - getLog().debug("Failed to resolve JSON descriptor as " + jsonArtifact); - } - return null; + private String getQuarkusCoreVersion() { + final List<Dependency> constraints = project.getDependencyManagement() == null ? Collections.emptyList() + : project.getDependencyManagement().getDependencies(); + for (Dependency d : constraints) { + if (d.getArtifactId().endsWith("quarkus-core") && d.getGroupId().equals("io.quarkus")) { + return d.getVersion(); } } - if (getLog().isDebugEnabled()) { - getLog().debug("Resolve JSON descriptor " + jsonArtifact); - } - return jsonArtifact; + return null; } protected void validateParameters() throws MojoExecutionException { @@ -276,53 +272,6 @@ protected void validateParameters() throws MojoExecutionException { protected abstract void doExecute(QuarkusProject quarkusProject, MessageWriter log) throws MojoExecutionException; - private String resolveValue(String expr) throws IOException { - if (expr.startsWith("${") && expr.endsWith("}")) { - final String name = expr.substring(2, expr.length() - 1); - final String v = project.getModel().getProperties().getProperty(name); - if (v == null) { - if (getLog().isDebugEnabled()) { - getLog().debug("Failed to resolve property " + name); - } - } - return v; - } - return expr; - } - - private List<Dependency> getManagedDependencies(MavenArtifactResolver resolver) throws IOException { - List<Dependency> managedDependencies = new ArrayList<>(); - Model model = project.getOriginalModel(); - DependencyManagement managed = model.getDependencyManagement(); - if (managed != null) { - managedDependencies.addAll(managed.getDependencies()); - } - Parent parent; - while ((parent = model.getParent()) != null) { - try { - ArtifactResult result = resolver.resolve(new DefaultArtifact( - parent.getGroupId(), - parent.getArtifactId(), - "pom", - ModelUtils.resolveVersion(parent.getVersion(), model))); - model = ModelUtils.readModel(result.getArtifact().getFile().toPath()); - managed = model.getDependencyManagement(); - if (managed != null) { - // Alexey Loubyansky: In Maven whatever is imported first has a priority - // So to match the maven way, we should be reading the root parent first - managedDependencies.addAll(0, managed.getDependencies()); - } - } catch (BootstrapMavenException e) { - // ignore - if (getLog().isDebugEnabled()) { - getLog().debug("Error while resolving descriptor", e); - } - break; - } - } - return managedDependencies; - } - private List<org.eclipse.aether.graph.Dependency> projectDependencies() throws MojoExecutionException { final List<org.eclipse.aether.graph.Dependency> deps = new ArrayList<>(); try { diff --git a/devtools/platform-descriptor-json-plugin/pom.xml b/devtools/platform-descriptor-json-plugin/pom.xml index a72f3f6b66dc14..3959a47c3c77c6 100644 --- a/devtools/platform-descriptor-json-plugin/pom.xml +++ b/devtools/platform-descriptor-json-plugin/pom.xml @@ -36,11 +36,6 @@ <groupId>org.wildfly.common</groupId> <artifactId>wildfly-common</artifactId> </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-platform-descriptor-resolver-json</artifactId> - <version>${project.version}</version> - </dependency> <dependency> <groupId>org.apache.maven.plugin-tools</groupId> <artifactId>maven-plugin-annotations</artifactId> diff --git a/devtools/platform-descriptor-json-plugin/src/main/java/io/quarkus/maven/GenerateExtensionsJsonMojo.java b/devtools/platform-descriptor-json-plugin/src/main/java/io/quarkus/maven/GenerateExtensionsJsonMojo.java index af15641550f6da..dfdc15c16c4a7e 100644 --- a/devtools/platform-descriptor-json-plugin/src/main/java/io/quarkus/maven/GenerateExtensionsJsonMojo.java +++ b/devtools/platform-descriptor-json-plugin/src/main/java/io/quarkus/maven/GenerateExtensionsJsonMojo.java @@ -64,17 +64,22 @@ import io.quarkus.bootstrap.resolver.maven.workspace.ModelUtils; import io.quarkus.bootstrap.util.IoUtils; import io.quarkus.bootstrap.util.ZipUtils; -import io.quarkus.dependencies.Extension; import io.quarkus.platform.tools.ToolsConstants; /** * This goal generates a list of extensions for a given BOM * and stores it in a JSON format file that is later used by the tools * as the catalog of available extensions. + * @deprecated in favor of {@link GeneratePlatformDescriptorJsonMojo} */ +@Deprecated @Mojo(name = "generate-extensions-json") public class GenerateExtensionsJsonMojo extends AbstractMojo { + private static final String GROUP_ID = "group-id"; + private static final String ARTIFACT_ID = "artifact-id"; + private static final String VERSION = "version"; + @Parameter(property = "bomGroupId", defaultValue = "${project.groupId}") private String bomGroupId; @@ -233,9 +238,9 @@ public void execute() throws MojoExecutionException, MojoFailureException { final JsonObjectBuilder platformJson = Json.createObjectBuilder(); // Add information about the BOM to it final JsonObjectBuilder bomJson = Json.createObjectBuilder(); - bomJson.add(Extension.GROUP_ID, bomGroupId); - bomJson.add(Extension.ARTIFACT_ID, bomArtifactId); - bomJson.add(Extension.VERSION, bomVersion); + bomJson.add(GROUP_ID, bomGroupId); + bomJson.add(ARTIFACT_ID, bomArtifactId); + bomJson.add(VERSION, bomVersion); platformJson.add("bom", bomJson.build()); // Add Quarkus version platformJson.add("quarkus-core-version", quarkusCoreVersion); @@ -409,8 +414,8 @@ private JsonNode processMetaInfDir(Artifact artifact, Path metaInfDir) final Path props = metaInfDir.resolve(BootstrapConstants.DESCRIPTOR_FILE_NAME); if (Files.exists(props)) { return mapper.createObjectNode() - .put(Extension.ARTIFACT_ID, artifact.getArtifactId()) - .put(Extension.GROUP_ID, artifact.getGroupId()) + .put(ARTIFACT_ID, artifact.getArtifactId()) + .put(GROUP_ID, artifact.getGroupId()) .put("version", artifact.getVersion()) .put("name", artifact.getArtifactId()); } else { @@ -428,7 +433,7 @@ private JsonNode processPlatformArtifact(Artifact artifact, Path descriptor, Obj try (InputStream is = Files.newInputStream(descriptor)) { ObjectNode object = mapper.readValue(is, ObjectNode.class); transformLegacyToNew(object, mapper); - debug("Adding Quarkus extension %s:%s", object.get(Extension.GROUP_ID), object.get(Extension.ARTIFACT_ID)); + debug("Adding Quarkus extension %s:%s", object.get(GROUP_ID), object.get(ARTIFACT_ID)); return object; } catch (IOException io) { throw new IOException("Failed to parse " + descriptor, io); @@ -452,15 +457,15 @@ private ObjectMapper getMapper(boolean yaml) { } private String extensionId(JsonObject extObject) { - String artId = extObject.getString(Extension.ARTIFACT_ID, ""); + String artId = extObject.getString(ARTIFACT_ID, ""); if (artId.isEmpty()) { getLog().warn("Missing artifactId in extension overrides in " + extObject.toString()); } - String groupId = extObject.getString(Extension.GROUP_ID, ""); + String groupId = extObject.getString(GROUP_ID, ""); if (groupId.isEmpty()) { return artId; } else { - return extObject.getString(Extension.GROUP_ID, "") + ":" + artId; + return extObject.getString(GROUP_ID, "") + ":" + artId; } } @@ -513,12 +518,12 @@ private void transformLegacyToNew(ObjectNode extObject, ObjectMapper mapper) { // just putting it // here for completenes if (extObject.get("groupId") != null) { - extObject.set(Extension.GROUP_ID, extObject.get("groupId")); + extObject.set(GROUP_ID, extObject.get("groupId")); extObject.remove("groupId"); } if (extObject.get("artifactId") != null) { - extObject.set(Extension.ARTIFACT_ID, extObject.get("artifactId")); + extObject.set(ARTIFACT_ID, extObject.get("artifactId")); extObject.remove("artifactId"); } @@ -550,31 +555,31 @@ private void transformLegacyToNew(ObjectNode extObject, ObjectMapper mapper) { public OverrideInfo getOverrideInfo(File overridesFile) throws MojoExecutionException { // Read the overrides file for the extensions (if it exists) - HashMap extOverrides = new HashMap<>(); + HashMap<String, JsonObject> extOverrides = new HashMap<>(); JsonObject theRest = null; if (overridesFile.isFile()) { info("Found overrides file %s", overridesFile); - try (JsonReader jsonReader = Json.createReader(new FileInputStream(overridesFile))) { - JsonObject overridesObject = jsonReader.readObject(); - JsonArray extOverrideObjects = overridesObject.getJsonArray("extensions"); - if (extOverrideObjects != null) { - // Put the extension overrides into a map keyed to their GAV - for (JsonValue val : extOverrideObjects) { - JsonObject extOverrideObject = val.asJsonObject(); - String key = extensionId(extOverrideObject); - extOverrides.put(key, extOverrideObject); + try (FileInputStream fileInputStream = new FileInputStream(overridesFile)) { + try (JsonReader jsonReader = Json.createReader(fileInputStream)) { + JsonObject overridesObject = jsonReader.readObject(); + JsonArray extOverrideObjects = overridesObject.getJsonArray("extensions"); + if (extOverrideObjects != null) { + // Put the extension overrides into a map keyed to their GAV + for (JsonValue val : extOverrideObjects) { + JsonObject extOverrideObject = val.asJsonObject(); + String key = extensionId(extOverrideObject); + extOverrides.put(key, extOverrideObject); + } } - } - theRest = overridesObject; + theRest = overridesObject; + } } catch (IOException e) { throw new MojoExecutionException("Failed to read " + overridesFile, e); } return new OverrideInfo(extOverrides, theRest); - - } else { - throw new MojoExecutionException(overridesFile + " not found."); } + return null; } private static class OverrideInfo { diff --git a/devtools/platform-descriptor-json-plugin/src/main/java/io/quarkus/maven/GeneratePlatformDescriptorJsonMojo.java b/devtools/platform-descriptor-json-plugin/src/main/java/io/quarkus/maven/GeneratePlatformDescriptorJsonMojo.java new file mode 100644 index 00000000000000..499aec8476c66b --- /dev/null +++ b/devtools/platform-descriptor-json-plugin/src/main/java/io/quarkus/maven/GeneratePlatformDescriptorJsonMojo.java @@ -0,0 +1,632 @@ +package io.quarkus.maven; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.maven.model.Model; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.Component; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.MavenProjectHelper; +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.impl.RemoteRepositoryManager; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.resolution.ArtifactDescriptorException; +import org.eclipse.aether.resolution.ArtifactDescriptorRequest; +import org.eclipse.aether.resolution.ArtifactRequest; +import org.eclipse.aether.resolution.ArtifactResolutionException; +import org.eclipse.aether.resolution.ArtifactResult; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; + +import io.quarkus.bootstrap.BootstrapConstants; +import io.quarkus.bootstrap.model.AppArtifact; +import io.quarkus.bootstrap.resolver.AppModelResolverException; +import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver; +import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; +import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; +import io.quarkus.bootstrap.resolver.maven.workspace.LocalWorkspace; +import io.quarkus.bootstrap.resolver.maven.workspace.ModelUtils; +import io.quarkus.bootstrap.util.IoUtils; +import io.quarkus.bootstrap.util.ZipUtils; +import io.quarkus.platform.descriptor.ProjectPlatformDescriptorJsonUtil; +import io.quarkus.platform.tools.ToolsConstants; +import io.quarkus.registry.catalog.Category; +import io.quarkus.registry.catalog.Extension; +import io.quarkus.registry.catalog.ExtensionOrigin; +import io.quarkus.registry.catalog.json.JsonCatalogMapperHelper; +import io.quarkus.registry.catalog.json.JsonCategory; +import io.quarkus.registry.catalog.json.JsonExtension; +import io.quarkus.registry.catalog.json.JsonExtensionCatalog; + +/** + * This goal generates a platform JSON descriptor for a given platform BOM. + */ +@Mojo(name = "generate-platform-descriptor-json") +public class GeneratePlatformDescriptorJsonMojo extends AbstractMojo { + + @Parameter(property = "quarkusCoreGroupId", defaultValue = ToolsConstants.QUARKUS_CORE_GROUP_ID) + private String quarkusCoreGroupId; + + @Parameter(property = "quarkusCoreArtifactId", defaultValue = ToolsConstants.QUARKUS_CORE_ARTIFACT_ID) + private String quarkusCoreArtifactId; + + @Parameter(property = "bomGroupId", defaultValue = "${project.groupId}") + private String bomGroupId; + + @Parameter(property = "bomArtifactId", defaultValue = "${project.artifactId}") + private String bomArtifactId; + + @Parameter(property = "bomVersion", defaultValue = "${project.version}") + private String bomVersion; + + /** file used for overrides - overridesFiles takes precedence over this file. **/ + @Parameter(property = "overridesFile", defaultValue = "${project.basedir}/src/main/resources/extensions-overrides.json") + private String overridesFile; + + @Parameter(property = "outputFile", defaultValue = "${project.build.directory}/${project.artifactId}-${project.version}-${project.version}.json") + private File outputFile; + + @Component + private RepositorySystem repoSystem; + + @Component + RemoteRepositoryManager remoteRepoManager; + + @Parameter(defaultValue = "${repositorySystemSession}", readonly = true) + private RepositorySystemSession repoSession; + + @Parameter(defaultValue = "${project.remoteProjectRepositories}", readonly = true, required = true) + private List<RemoteRepository> repos; + + @Component + private MavenProject project; + @Component + private MavenProjectHelper projectHelper; + + /** + * Group ID's that we know don't contain extensions. This can speed up the process + * by preventing the download of artifacts that are not required. + */ + @Parameter + private Set<String> ignoredGroupIds = new HashSet<>(0); + + @Parameter + private boolean skipArtifactIdCheck; + + @Parameter(property = "skipBomCheck") + private boolean skipBomCheck; + + @Parameter(property = "resolveDependencyManagement") + boolean resolveDependencyManagement; + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + + final Artifact jsonArtifact = new DefaultArtifact(project.getGroupId(), project.getArtifactId(), project.getVersion(), + "json", project.getVersion()); + if (!skipArtifactIdCheck) { + final String expectedArtifactId = bomArtifactId + BootstrapConstants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX; + if (!jsonArtifact.getArtifactId().equals(expectedArtifactId)) { + throw new MojoExecutionException( + "The project's artifactId " + project.getArtifactId() + " is expected to be " + expectedArtifactId); + } + if (!jsonArtifact.getGroupId().equals(bomGroupId)) { + throw new MojoExecutionException("The project's groupId " + project.getGroupId() + + " is expected to match the groupId of the BOM which is " + bomGroupId); + } + if (!jsonArtifact.getVersion().equals(bomVersion)) { + throw new MojoExecutionException("The project's version " + project.getVersion() + + " is expected to match the version of the BOM which is " + bomVersion); + } + } + + // Get the BOM artifact + final DefaultArtifact bomArtifact = new DefaultArtifact(bomGroupId, bomArtifactId, "", "pom", bomVersion); + info("Generating catalog of extensions for %s", bomArtifact); + + // if the BOM is generated and has replaced the original one, to pick up the generated content + // we should read the dependencyManagement from the generated pom.xml + List<Dependency> deps; + if (resolveDependencyManagement) { + getLog().debug("Resolving dependencyManagement from the artifact descriptor"); + deps = dependencyManagementFromDescriptor(bomArtifact); + } else { + deps = dependencyManagementFromProject(); + if (deps == null) { + deps = dependencyManagementFromResolvedPom(bomArtifact); + } + } + if (deps.isEmpty()) { + getLog().warn("BOM " + bomArtifact + " does not include any dependency"); + return; + } + + List<OverrideInfo> allOverrides = new ArrayList<>(); + for (String path : overridesFile.split(",")) { + OverrideInfo overrideInfo = getOverrideInfo(new File(path.trim())); + if (overrideInfo != null) { + allOverrides.add(overrideInfo); + } + } + + final JsonExtensionCatalog platformJson = new JsonExtensionCatalog(); + final String platformId = jsonArtifact.getGroupId() + ":" + jsonArtifact.getArtifactId() + ":" + + jsonArtifact.getClassifier() + + ":" + jsonArtifact.getExtension() + ":" + jsonArtifact.getVersion(); + platformJson.setId(platformId); + platformJson.setBom(ArtifactCoords.pom(bomGroupId, bomArtifactId, bomVersion)); + platformJson.setPlatform(true); + + final List<AppArtifact> importedDescriptors = deps.stream().filter( + d -> d.getArtifact().getArtifactId().endsWith(BootstrapConstants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX) + && d.getArtifact().getExtension().equals("json") + && !(d.getArtifact().getArtifactId().equals(jsonArtifact.getArtifactId()) + && d.getArtifact().getGroupId().equals(jsonArtifact.getGroupId()))) + .map(d -> new AppArtifact(d.getArtifact().getGroupId(), d.getArtifact().getArtifactId(), + d.getArtifact().getClassifier(), d.getArtifact().getExtension(), d.getArtifact().getVersion())) + .collect(Collectors.toList()); + + Map<ArtifactKey, Extension> inheritedExtensions = Collections.emptyMap(); + if (!importedDescriptors.isEmpty()) { + final MavenArtifactResolver mvnResolver; + try { + mvnResolver = MavenArtifactResolver.builder() + .setRepositorySystem(repoSystem) + .setRemoteRepositoryManager(remoteRepoManager) + .setRepositorySystemSession(repoSession) + .setRemoteRepositories(repos) + .setWorkspaceDiscovery(false) + .build(); + } catch (BootstrapMavenException e) { + throw new MojoExecutionException("Failed to initialize Maven artifact resolver", e); + } + final JsonExtensionCatalog baseCatalog; + try { + baseCatalog = ProjectPlatformDescriptorJsonUtil + .resolveCatalog(new BootstrapAppModelResolver(mvnResolver), importedDescriptors); + } catch (AppModelResolverException e) { + throw new MojoExecutionException("Failed to resolver inherited platform descriptor", e); + } + platformJson.setDerivedFrom(baseCatalog.getDerivedFrom()); + + final List<Extension> extensions = baseCatalog.getExtensions(); + if (!extensions.isEmpty()) { + inheritedExtensions = new HashMap<>(extensions.size()); + for (Extension e : extensions) { + inheritedExtensions.put(e.getArtifact().getKey(), e); + } + } + + platformJson.setMetadata(baseCatalog.getMetadata()); + } + + // Create a JSON array of extension descriptors + final List<io.quarkus.registry.catalog.Extension> extListJson = new ArrayList<>(); + platformJson.setExtensions(extListJson); + String quarkusCoreVersion = null; + boolean jsonFoundInBom = false; + for (Dependency dep : deps) { + final Artifact artifact = dep.getArtifact(); + + if (!skipBomCheck && !jsonFoundInBom) { + jsonFoundInBom = artifact.getArtifactId().equals(jsonArtifact.getArtifactId()) + && artifact.getGroupId().equals(jsonArtifact.getGroupId()) + && artifact.getExtension().equals(jsonArtifact.getExtension()) + && artifact.getClassifier().equals(jsonArtifact.getClassifier()) + && artifact.getVersion().equals(jsonArtifact.getVersion()); + } + + if (ignoredGroupIds.contains(artifact.getGroupId()) + || !artifact.getExtension().equals("jar") + || "javadoc".equals(artifact.getClassifier()) + || "tests".equals(artifact.getClassifier()) + || "sources".equals(artifact.getClassifier())) { + continue; + } + + if (artifact.getArtifactId().equals(quarkusCoreArtifactId) + && artifact.getGroupId().equals(quarkusCoreGroupId)) { + quarkusCoreVersion = artifact.getVersion(); + } + ArtifactResult resolved = null; + try { + resolved = repoSystem.resolveArtifact(repoSession, + new ArtifactRequest().setRepositories(repos).setArtifact(artifact)); + JsonExtension extension = processDependency(resolved.getArtifact()); + if (extension != null) { + Extension inherited = inheritedExtensions.get(extension.getArtifact().getKey()); + final List<ExtensionOrigin> origins; + if (inherited != null) { + origins = new ArrayList<>(inherited.getOrigins().size() + 1); + origins.addAll(inherited.getOrigins()); + origins.add(platformJson); + } else { + origins = Arrays.asList(platformJson); + } + extension.setOrigins(origins); + String key = extensionId(extension); + for (OverrideInfo info : allOverrides) { + io.quarkus.registry.catalog.Extension extOverride = info.getExtOverrides().get(key); + if (extOverride != null) { + extension = mergeObject(extension, extOverride); + } + } + extListJson.add(extension); + } + } catch (ArtifactResolutionException e) { + // there are some parent poms that appear as jars for some reason + debug("Failed to resolve dependency %s defined in %s", artifact, bomArtifact); + } catch (IOException e) { + throw new MojoExecutionException("Failed to process dependency " + artifact, e); + } + } + + if (!skipBomCheck && !jsonFoundInBom) { + throw new MojoExecutionException( + "Failed to locate " + jsonArtifact + " in the dependencyManagement section of " + bomArtifact); + } + if (quarkusCoreVersion == null) { + throw new MojoExecutionException("Failed to determine the Quarkus Core version for " + bomArtifact); + } + platformJson.setQuarkusCoreVersion(quarkusCoreVersion); + + for (OverrideInfo info : allOverrides) { + if (info.getTheRest() != null) { + if (!info.getTheRest().getCategories().isEmpty()) { + if (platformJson.getCategories().isEmpty()) { + platformJson.setCategories(info.getTheRest().getCategories()); + } else { + info.getTheRest().getCategories().stream().forEach(c -> { + boolean found = false; + for (Category platformC : platformJson.getCategories()) { + if (platformC.getId().equals(c.getId())) { + found = true; + JsonCategory jsonC = (JsonCategory) platformC; + if (c.getDescription() != null) { + jsonC.setDescription(c.getDescription()); + } + if (!c.getMetadata().isEmpty()) { + if (jsonC.getMetadata().isEmpty()) { + jsonC.setMetadata(c.getMetadata()); + } else { + jsonC.getMetadata().putAll(c.getMetadata()); + } + } + if (c.getName() != null) { + jsonC.setName(c.getName()); + } + } + break; + } + if (!found) { + platformJson.getCategories().add(c); + } + }); + } + } + } + if (!info.getTheRest().getMetadata().isEmpty()) { + if (platformJson.getMetadata().isEmpty()) { + platformJson.setMetadata(info.getTheRest().getMetadata()); + } else { + platformJson.getMetadata().putAll(info.getTheRest().getMetadata()); + } + } + } + // Write the JSON to the output file + final File outputDir = outputFile.getParentFile(); + if (outputFile.exists()) { + outputFile.delete(); + } else if (!outputDir.exists()) { + if (!outputDir.mkdirs()) { + throw new MojoExecutionException("Failed to create output directory " + outputDir); + } + } + try { + JsonCatalogMapperHelper.serialize(platformJson, outputFile.toPath().getParent().resolve(outputFile.getName())); + } catch (IOException e) { + throw new MojoExecutionException("Failed to persist the platform descriptor", e); + } + info("Extensions file written to %s", outputFile); + + // this is necessary to sometimes be able to resolve the artifacts from the workspace + final File published = new File(project.getBuild().getDirectory(), LocalWorkspace.getFileName(jsonArtifact)); + if (!outputDir.equals(published)) { + try { + IoUtils.copy(outputFile.toPath(), published.toPath()); + } catch (IOException e) { + throw new MojoExecutionException("Failed to copy " + outputFile + " to " + published); + } + } + projectHelper.attachArtifact(project, jsonArtifact.getExtension(), jsonArtifact.getClassifier(), published); + } + + private List<Dependency> dependencyManagementFromDescriptor(Artifact bomArtifact) throws MojoExecutionException { + try { + return repoSystem + .readArtifactDescriptor(repoSession, + new ArtifactDescriptorRequest().setRepositories(repos).setArtifact(bomArtifact)) + .getManagedDependencies(); + } catch (ArtifactDescriptorException e) { + throw new MojoExecutionException("Failed to read descriptor of " + bomArtifact, e); + } + } + + private List<Dependency> dependencyManagementFromResolvedPom(Artifact bomArtifact) throws MojoExecutionException { + final Path pomXml; + try { + pomXml = repoSystem + .resolveArtifact(repoSession, new ArtifactRequest().setArtifact(bomArtifact).setRepositories(repos)) + .getArtifact().getFile().toPath(); + } catch (ArtifactResolutionException e) { + throw new MojoExecutionException("Failed to resolve " + bomArtifact, e); + } + return readDependencyManagement(pomXml); + } + + private List<Dependency> dependencyManagementFromProject() throws MojoExecutionException { + // if the configured BOM coordinates are not matching the current project + // the current project's POM isn't the right source + if (!project.getArtifact().getArtifactId().equals(bomArtifactId) + || !project.getArtifact().getVersion().equals(bomVersion) + || !project.getArtifact().getGroupId().equals(bomGroupId) + || !project.getFile().exists()) { + return null; + } + return readDependencyManagement(project.getFile().toPath()); + } + + private List<Dependency> readDependencyManagement(Path pomXml) throws MojoExecutionException { + if (getLog().isDebugEnabled()) { + getLog().debug("Reading dependencyManagement from " + pomXml); + } + final Model bomModel; + try { + bomModel = ModelUtils.readModel(pomXml); + } catch (IOException e) { + throw new MojoExecutionException("Failed to parse " + project.getFile(), e); + } + + // if the POM has a parent then we better resolve the descriptor + if (bomModel.getParent() != null) { + throw new MojoExecutionException(pomXml + + " has a parent, in which case it is recommended to set 'resolveDependencyManagement' parameter to true"); + } + + if (bomModel.getDependencyManagement() == null) { + return Collections.emptyList(); + } + final List<org.apache.maven.model.Dependency> modelDeps = bomModel.getDependencyManagement().getDependencies(); + if (modelDeps.isEmpty()) { + return Collections.emptyList(); + } + + final List<Dependency> deps = new ArrayList<>(modelDeps.size()); + for (org.apache.maven.model.Dependency modelDep : modelDeps) { + final Artifact artifact = new DefaultArtifact(modelDep.getGroupId(), modelDep.getArtifactId(), + modelDep.getClassifier(), modelDep.getType(), modelDep.getVersion()); + // exclusions aren't relevant in this context + deps.add(new Dependency(artifact, modelDep.getScope(), modelDep.isOptional(), Collections.emptyList())); + } + return deps; + } + + private JsonExtension processDependency(Artifact artifact) throws IOException { + return processDependencyToObjectNode(artifact); + } + + private JsonExtension processDependencyToObjectNode(Artifact artifact) throws IOException { + final Path path = artifact.getFile().toPath(); + if (Files.isDirectory(path)) { + return processMetaInfDir(artifact, path.resolve(BootstrapConstants.META_INF)); + } else { + try (FileSystem artifactFs = ZipUtils.newFileSystem(path)) { + return processMetaInfDir(artifact, artifactFs.getPath(BootstrapConstants.META_INF)); + } + } + } + + /** + * Load and return javax.jsonObject based on yaml, json or properties file. + * + * @param artifact + * @param metaInfDir + * @return + * @throws IOException + */ + private JsonExtension processMetaInfDir(Artifact artifact, Path metaInfDir) + throws IOException { + + ObjectMapper mapper = null; + + if (!Files.exists(metaInfDir)) { + return null; + } + Path jsonOrYaml = null; + + Path yaml = metaInfDir.resolve(BootstrapConstants.QUARKUS_EXTENSION_FILE_NAME); + if (Files.exists(yaml)) { + mapper = getMapper(true); + jsonOrYaml = yaml; + } else { + mapper = getMapper(false); + Path json = metaInfDir.resolve(BootstrapConstants.EXTENSION_PROPS_JSON_FILE_NAME); + if (!Files.exists(json)) { + final Path props = metaInfDir.resolve(BootstrapConstants.DESCRIPTOR_FILE_NAME); + if (Files.exists(props)) { + final JsonExtension e = new JsonExtension(); + e.setArtifact(new ArtifactCoords(artifact.getGroupId(), artifact.getArtifactId(), artifact.getClassifier(), + artifact.getExtension(), artifact.getVersion())); + e.setName(artifact.getArtifactId()); + return e; + } + return null; + } else { + jsonOrYaml = json; + } + } + return processPlatformArtifact(artifact, jsonOrYaml, mapper); + } + + private JsonExtension processPlatformArtifact(Artifact artifact, Path descriptor, ObjectMapper mapper) + throws IOException { + try (InputStream is = Files.newInputStream(descriptor)) { + JsonExtension legacy = mapper.readValue(is, JsonExtension.class); + JsonExtension object = transformLegacyToNew(legacy); + debug("Adding Quarkus extension %s", object.getArtifact()); + return object; + } catch (IOException io) { + throw new IOException("Failed to parse " + descriptor, io); + } + } + + private ObjectMapper getMapper(boolean yaml) { + + if (yaml) { + YAMLFactory yf = new YAMLFactory(); + return JsonCatalogMapperHelper.initMapper(new ObjectMapper(yf)); + } else { + return JsonCatalogMapperHelper.mapper(); + } + } + + private String extensionId(io.quarkus.registry.catalog.Extension extObject) { + return extObject.getArtifact().getGroupId() + ":" + extObject.getArtifact().getArtifactId(); + } + + private JsonExtension mergeObject(JsonExtension extObject, io.quarkus.registry.catalog.Extension extOverride) { + if (extOverride.getArtifact() != null) { + extObject.setArtifact(extOverride.getArtifact()); + } + if (extOverride.getCodestart() != null) { + extObject.setCodestart(extOverride.getCodestart()); + } + if (extOverride.getDescription() != null) { + extObject.setDescription(extOverride.getDescription()); + } + if (extOverride.getGuide() != null) { + extObject.setGuide(extOverride.getGuide()); + } + if (!extOverride.getKeywords().isEmpty()) { + extObject.setKeywords(extOverride.getKeywords()); + } + if (!extOverride.getMetadata().isEmpty()) { + if (extObject.getMetadata().isEmpty()) { + extObject.setMetadata(extOverride.getMetadata()); + } else { + extObject.getMetadata().putAll(extOverride.getMetadata()); + } + } + if (extOverride.getName() != null) { + extObject.setName(extOverride.getName()); + } + if (!extOverride.getOrigins().isEmpty()) { + extObject.setOrigins(extOverride.getOrigins()); + } + if (extOverride.getShortName() != null) { + extObject.setShortName(extOverride.getShortName()); + } + return extObject; + } + + private void info(String msg, Object... args) { + if (!getLog().isInfoEnabled()) { + return; + } + if (args.length == 0) { + getLog().info(msg); + return; + } + getLog().info(String.format(msg, args)); + } + + private void debug(String msg, Object... args) { + if (!getLog().isDebugEnabled()) { + return; + } + if (args.length == 0) { + getLog().debug(msg); + return; + } + getLog().debug(String.format(msg, args)); + } + + private JsonExtension transformLegacyToNew(JsonExtension extObject) { + final Map<String, Object> metadata = extObject.getMetadata(); + final Object labels = metadata.get("labels"); + if (labels != null) { + metadata.put("keywords", labels); + metadata.remove("labels"); + } + return extObject; + } + + public OverrideInfo getOverrideInfo(File overridesFile) throws MojoExecutionException { + // Read the overrides file for the extensions (if it exists) + HashMap<String, io.quarkus.registry.catalog.Extension> extOverrides = new HashMap<>(); + JsonExtensionCatalog theRest = null; + if (overridesFile.isFile()) { + info("Found overrides file %s", overridesFile); + try { + JsonExtensionCatalog overridesObject = JsonCatalogMapperHelper.deserialize(overridesFile.toPath(), + JsonExtensionCatalog.class); + List<io.quarkus.registry.catalog.Extension> extensionsOverrides = overridesObject.getExtensions(); + if (!extensionsOverrides.isEmpty()) { + // Put the extension overrides into a map keyed to their GAV + for (io.quarkus.registry.catalog.Extension extOverride : extensionsOverrides) { + String key = extensionId(extOverride); + extOverrides.put(key, extOverride); + } + } + + theRest = overridesObject; + } catch (IOException e) { + throw new MojoExecutionException("Failed to read " + overridesFile, e); + } + return new OverrideInfo(extOverrides, theRest); + } + return null; + } + + private static class OverrideInfo { + private Map<String, io.quarkus.registry.catalog.Extension> extOverrides; + private JsonExtensionCatalog theRest; + + public OverrideInfo(Map<String, io.quarkus.registry.catalog.Extension> extOverrides, + JsonExtensionCatalog theRest) { + this.extOverrides = extOverrides; + this.theRest = theRest; + } + + public Map<String, io.quarkus.registry.catalog.Extension> getExtOverrides() { + return extOverrides; + } + + public JsonExtensionCatalog getTheRest() { + return theRest; + } + } +} diff --git a/devtools/platform-descriptor-json-plugin/src/main/java/io/quarkus/maven/ValidateExtensionsJsonMojo.java b/devtools/platform-descriptor-json-plugin/src/main/java/io/quarkus/maven/ValidateExtensionsJsonMojo.java index b33fb8ec0f7861..88cb63cc48abf2 100644 --- a/devtools/platform-descriptor-json-plugin/src/main/java/io/quarkus/maven/ValidateExtensionsJsonMojo.java +++ b/devtools/platform-descriptor-json-plugin/src/main/java/io/quarkus/maven/ValidateExtensionsJsonMojo.java @@ -29,11 +29,11 @@ import org.eclipse.aether.repository.RemoteRepository; import io.quarkus.bootstrap.BootstrapConstants; -import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver; +import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; -import io.quarkus.dependencies.Extension; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.descriptor.resolver.json.QuarkusJsonPlatformDescriptorResolver; +import io.quarkus.registry.catalog.Extension; +import io.quarkus.registry.catalog.json.JsonCatalogMapperHelper; +import io.quarkus.registry.catalog.json.JsonExtensionCatalog; /** * This goal validates a given JSON descriptor. @@ -101,17 +101,29 @@ public void execute() throws MojoExecutionException, MojoFailureException { throw new MojoExecutionException("Failed to initialize maven artifact resolver", e); } - final QuarkusPlatformDescriptor descriptor = QuarkusJsonPlatformDescriptorResolver.newInstance() - .setArtifactResolver(new BootstrapAppModelResolver(mvn)) - .resolveFromJson(jsonGroupId, jsonArtifactId, jsonVersion, jsonVersion); + final Artifact artifact = new DefaultArtifact(jsonGroupId, jsonArtifactId, jsonVersion, "json", jsonVersion); + final Path jsonPath; + try { + jsonPath = mvn.resolve(artifact).getArtifact().getFile().toPath(); + } catch (BootstrapMavenException e) { + throw new MojoExecutionException("Failed to resolve platform descriptor " + artifact, e); + } + + JsonExtensionCatalog catalog; + try { + catalog = JsonCatalogMapperHelper.deserialize(jsonPath, JsonExtensionCatalog.class); + } catch (IOException e) { + throw new MojoExecutionException("Failed to deserialize extension catalog " + jsonPath, e); + } + final ArtifactCoords bomCoords = catalog.getBom(); - final DefaultArtifact bomArtifact = new DefaultArtifact(descriptor.getBomGroupId(), - descriptor.getBomArtifactId(), null, "pom", descriptor.getBomVersion()); + final DefaultArtifact bomArtifact = new DefaultArtifact(bomCoords.getGroupId(), + bomCoords.getArtifactId(), bomCoords.getClassifier(), bomCoords.getType(), bomCoords.getVersion()); final Map<String, Artifact> bomExtensions = collectBomExtensions(mvn, bomArtifact); List<Extension> missingFromBom = Collections.emptyList(); - for (Extension ext : descriptor.getExtensions()) { - if (bomExtensions.remove(ext.getGroupId() + ":" + ext.getArtifactId()) == null) { + for (Extension ext : catalog.getExtensions()) { + if (bomExtensions.remove(ext.getArtifact().getGroupId() + ":" + ext.getArtifact().getArtifactId()) == null) { if (missingFromBom.isEmpty()) { missingFromBom = new ArrayList<>(); } @@ -134,8 +146,7 @@ public void execute() throws MojoExecutionException, MojoFailureException { getLog().error("Extensions from " + jsonGroupId + ":" + jsonArtifactId + ":" + jsonVersion + " missing from " + bomArtifact); for (Extension e : missingFromBom) { - getLog().error("- " + e.getGroupId() + ":" + e.getArtifactId() + ":" + e.getClassifier() + ":" + e.getType() - + ":" + e.getVersion()); + getLog().error("- " + e.getArtifact()); } } throw new MojoExecutionException("Extensions referenced in " + bomArtifact + " and included in " + jsonGroupId + ":" diff --git a/devtools/platform-descriptor-json/src/main/java/io/quarkus/platform/descriptor/loader/json/impl/QuarkusJsonPlatformBom.java b/devtools/platform-descriptor-json/src/main/java/io/quarkus/platform/descriptor/loader/json/impl/QuarkusJsonPlatformBom.java deleted file mode 100644 index 691a6720279323..00000000000000 --- a/devtools/platform-descriptor-json/src/main/java/io/quarkus/platform/descriptor/loader/json/impl/QuarkusJsonPlatformBom.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.quarkus.platform.descriptor.loader.json.impl; - -public class QuarkusJsonPlatformBom { - - public String groupId; - public String artifactId; - public String version; -} diff --git a/devtools/platform-descriptor-json/src/main/java/io/quarkus/platform/descriptor/loader/json/impl/QuarkusJsonPlatformDescriptor.java b/devtools/platform-descriptor-json/src/main/java/io/quarkus/platform/descriptor/loader/json/impl/QuarkusJsonPlatformDescriptor.java deleted file mode 100644 index 36b136f64b3125..00000000000000 --- a/devtools/platform-descriptor-json/src/main/java/io/quarkus/platform/descriptor/loader/json/impl/QuarkusJsonPlatformDescriptor.java +++ /dev/null @@ -1,170 +0,0 @@ -package io.quarkus.platform.descriptor.loader.json.impl; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Serializable; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; - -import org.apache.maven.model.Dependency; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import io.quarkus.dependencies.Category; -import io.quarkus.dependencies.Extension; -import io.quarkus.devtools.messagewriter.MessageWriter; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.descriptor.ResourceInputStreamConsumer; -import io.quarkus.platform.descriptor.ResourcePathConsumer; -import io.quarkus.platform.descriptor.loader.json.ResourceLoader; - -public class QuarkusJsonPlatformDescriptor implements QuarkusPlatformDescriptor, Serializable { - - private String bomGroupId; - private String bomArtifactId; - private String bomVersion; - private String quarkusVersion; - - private List<Extension> extensions = Collections.emptyList(); - private List<Category> categories = Collections.emptyList(); - private Map<String, Object> metadata = Collections.emptyMap(); - private transient ResourceLoader resourceLoader; - private transient MessageWriter log; - - public QuarkusJsonPlatformDescriptor() { - } - - public void setBom(QuarkusJsonPlatformBom bom) { - bomGroupId = bom.groupId; - bomArtifactId = bom.artifactId; - bomVersion = bom.version; - } - - public void setQuarkusCoreVersion(String quarkusVersion) { - this.quarkusVersion = quarkusVersion; - } - - public void setExtensions(List<Extension> extensions) { - this.extensions = extensions; - } - - public void setMetadata(Map<String, Object> metadata) { - this.metadata = metadata; - } - - void setResourceLoader(ResourceLoader resourceLoader) { - this.resourceLoader = resourceLoader; - } - - void setMessageWriter(MessageWriter log) { - this.log = log; - } - - void setQuarkusVersion(String quarkusVersion) { - this.quarkusVersion = quarkusVersion; - } - - private MessageWriter getLog() { - return log == null ? log = MessageWriter.info() : log; - } - - @Override - public String getBomGroupId() { - return bomGroupId; - } - - @Override - public String getBomArtifactId() { - return bomArtifactId; - } - - @Override - public String getBomVersion() { - return bomVersion; - } - - @Override - public String getQuarkusVersion() { - return quarkusVersion; - } - - @Override - public List<Extension> getExtensions() { - return extensions; - } - - @Override - public Map<String, Object> getMetadata() { - return metadata; - } - - @Override - @JsonIgnore - public List<Dependency> getManagedDependencies() { - throw new UnsupportedOperationException(); - } - - @Override - public String getTemplate(String name) { - getLog().debug("Loading Quarkus project template %s", name); - if (resourceLoader == null) { - throw new IllegalStateException("Resource loader has not been provided"); - } - try { - return resourceLoader.loadResource(name, is -> { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { - return reader.lines().collect(Collectors.joining("\n")); - } - }); - } catch (IOException e) { - throw new IllegalStateException("Failed to load " + name, e); - } - } - - @Override - public <T> T loadResource(String name, ResourceInputStreamConsumer<T> consumer) throws IOException { - getLog().debug("Loading Quarkus platform resource %s", name); - if (resourceLoader == null) { - throw new IllegalStateException("Resource loader has not been provided"); - } - return resourceLoader.loadResource(name, consumer); - } - - @Override - public <T> T loadResourceAsPath(String name, ResourcePathConsumer<T> consumer) throws IOException { - getLog().debug("Loading Quarkus platform resource %s", name); - if (resourceLoader == null) { - throw new IllegalStateException("Resource loader has not been provided"); - } - return resourceLoader.loadResourceAsPath(name, consumer); - } - - @Override - public List<Category> getCategories() { - return categories; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - QuarkusJsonPlatformDescriptor that = (QuarkusJsonPlatformDescriptor) o; - return bomGroupId.equals(that.bomGroupId) && - bomArtifactId.equals(that.bomArtifactId) && - bomVersion.equals(that.bomVersion); - } - - @Override - public int hashCode() { - return Objects.hash(bomGroupId, bomArtifactId, bomVersion); - } -} diff --git a/devtools/platform-descriptor-json/src/main/java/io/quarkus/platform/descriptor/loader/json/impl/QuarkusJsonPlatformDescriptorLoaderBootstrap.java b/devtools/platform-descriptor-json/src/main/java/io/quarkus/platform/descriptor/loader/json/impl/QuarkusJsonPlatformDescriptorLoaderBootstrap.java deleted file mode 100644 index 5c3134d7d70cba..00000000000000 --- a/devtools/platform-descriptor-json/src/main/java/io/quarkus/platform/descriptor/loader/json/impl/QuarkusJsonPlatformDescriptorLoaderBootstrap.java +++ /dev/null @@ -1,87 +0,0 @@ -package io.quarkus.platform.descriptor.loader.json.impl; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Properties; -import java.util.function.Function; - -import io.quarkus.maven.utilities.MojoUtils; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.descriptor.loader.QuarkusPlatformDescriptorLoader; -import io.quarkus.platform.descriptor.loader.QuarkusPlatformDescriptorLoaderContext; -import io.quarkus.platform.descriptor.loader.json.ArtifactResolver; -import io.quarkus.platform.descriptor.loader.json.QuarkusJsonPlatformDescriptorLoaderContext; - -/** - * This class is used to bootstrap the Quarkus platform descriptor from the classpath only. - */ -public class QuarkusJsonPlatformDescriptorLoaderBootstrap - implements QuarkusPlatformDescriptorLoader<QuarkusPlatformDescriptor, QuarkusPlatformDescriptorLoaderContext> { - - private static InputStream getResourceStream(String relativePath) { - final InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(relativePath); - if (is == null) { - throw new IllegalStateException("Failed to locate " + relativePath + " on the classpath"); - } - return is; - } - - @Override - public QuarkusPlatformDescriptor load(QuarkusPlatformDescriptorLoaderContext context) { - - context.getMessageWriter().debug("Loading the default Quarkus Platform descriptor from the classpath"); - - final Properties props = new Properties(); - final InputStream quarkusProps = getResourceStream("quarkus.properties"); - try { - props.load(quarkusProps); - } catch (IOException e) { - throw new IllegalStateException("Failed to load properties quarkus.properties", e); - } - - final Path resourceRoot; - try { - resourceRoot = MojoUtils.getClassOrigin(QuarkusJsonPlatformDescriptorLoaderBootstrap.class); - } catch (IOException e) { - throw new IllegalStateException("Failed to determine the resource root for " + getClass().getName(), e); - } - - final ArtifactResolver resolver = new ArtifactResolver() { - @Override - public <T> T process(String groupId, String artifactId, String classifier, String type, String version, - Function<Path, T> processor) { - throw new UnsupportedOperationException(); - } - }; - - return new QuarkusJsonPlatformDescriptorLoaderImpl() - .load(new QuarkusJsonPlatformDescriptorLoaderContext(resolver, context.getMessageWriter()) { - @Override - public <T> T parseJson(Function<InputStream, T> parser) { - if (Files.isDirectory(resourceRoot)) { - return doParse(resourceRoot.resolve("quarkus-bom-descriptor/extensions.json"), parser); - } - try (FileSystem fs = FileSystems.newFileSystem(resourceRoot, null)) { - return doParse(fs.getPath("/quarkus-bom-descriptor/extensions.json"), parser); - } catch (IOException e) { - throw new IllegalStateException("Failed to open " + resourceRoot, e); - } - } - }); - } - - private static <T> T doParse(Path p, Function<InputStream, T> parser) { - if (!Files.exists(p)) { - throw new IllegalStateException("Path does not exist: " + p); - } - try (InputStream is = Files.newInputStream(p)) { - return parser.apply(is); - } catch (IOException e) { - throw new IllegalStateException("Failed to read " + p, e); - } - } -} diff --git a/devtools/platform-descriptor-json/src/main/java/io/quarkus/platform/descriptor/loader/json/impl/QuarkusJsonPlatformDescriptorLoaderImpl.java b/devtools/platform-descriptor-json/src/main/java/io/quarkus/platform/descriptor/loader/json/impl/QuarkusJsonPlatformDescriptorLoaderImpl.java deleted file mode 100644 index 75adb5f1ad0a2c..00000000000000 --- a/devtools/platform-descriptor-json/src/main/java/io/quarkus/platform/descriptor/loader/json/impl/QuarkusJsonPlatformDescriptorLoaderImpl.java +++ /dev/null @@ -1,39 +0,0 @@ -package io.quarkus.platform.descriptor.loader.json.impl; - -import java.io.IOException; - -import com.fasterxml.jackson.core.json.JsonReadFeature; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.PropertyNamingStrategies; -import com.fasterxml.jackson.databind.json.JsonMapper; - -import io.quarkus.platform.descriptor.loader.json.QuarkusJsonPlatformDescriptorLoader; -import io.quarkus.platform.descriptor.loader.json.QuarkusJsonPlatformDescriptorLoaderContext; - -public class QuarkusJsonPlatformDescriptorLoaderImpl - implements QuarkusJsonPlatformDescriptorLoader<QuarkusJsonPlatformDescriptor> { - - @Override - public QuarkusJsonPlatformDescriptor load(final QuarkusJsonPlatformDescriptorLoaderContext context) { - - final QuarkusJsonPlatformDescriptor platform = context - .parseJson(is -> { - try { - ObjectMapper mapper = JsonMapper.builder() - .enable(JsonReadFeature.ALLOW_JAVA_COMMENTS) - .enable(JsonReadFeature.ALLOW_LEADING_ZEROS_FOR_NUMBERS) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .propertyNamingStrategy(PropertyNamingStrategies.KEBAB_CASE) - .build(); - return mapper.readValue(is, QuarkusJsonPlatformDescriptor.class); - } catch (IOException e) { - throw new RuntimeException("Failed to parse JSON stream", e); - } - }); - platform.setResourceLoader(context.getResourceLoader()); - platform.setMessageWriter(context.getMessageWriter()); - - return platform; - } -} diff --git a/devtools/platform-descriptor-json/src/main/resources/META-INF/services/io.quarkus.platform.descriptor.loader.QuarkusPlatformDescriptorLoader b/devtools/platform-descriptor-json/src/main/resources/META-INF/services/io.quarkus.platform.descriptor.loader.QuarkusPlatformDescriptorLoader deleted file mode 100644 index 54b44251eaa4f8..00000000000000 --- a/devtools/platform-descriptor-json/src/main/resources/META-INF/services/io.quarkus.platform.descriptor.loader.QuarkusPlatformDescriptorLoader +++ /dev/null @@ -1 +0,0 @@ -io.quarkus.platform.descriptor.loader.json.impl.QuarkusJsonPlatformDescriptorLoaderBootstrap \ No newline at end of file diff --git a/devtools/platform-descriptor-json/src/main/resources/META-INF/services/io.quarkus.platform.descriptor.loader.json.QuarkusJsonPlatformDescriptorLoader b/devtools/platform-descriptor-json/src/main/resources/META-INF/services/io.quarkus.platform.descriptor.loader.json.QuarkusJsonPlatformDescriptorLoader deleted file mode 100644 index 067557f6396e3e..00000000000000 --- a/devtools/platform-descriptor-json/src/main/resources/META-INF/services/io.quarkus.platform.descriptor.loader.json.QuarkusJsonPlatformDescriptorLoader +++ /dev/null @@ -1 +0,0 @@ -io.quarkus.platform.descriptor.loader.json.impl.QuarkusJsonPlatformDescriptorLoaderImpl \ No newline at end of file diff --git a/devtools/platform-descriptor-json/src/test/java/io/quarkus/platform/descriptor/tests/PlatformDescriptorLoaderTest.java b/devtools/platform-descriptor-json/src/test/java/io/quarkus/platform/descriptor/tests/PlatformDescriptorLoaderTest.java deleted file mode 100644 index db36ce32603f2c..00000000000000 --- a/devtools/platform-descriptor-json/src/test/java/io/quarkus/platform/descriptor/tests/PlatformDescriptorLoaderTest.java +++ /dev/null @@ -1,65 +0,0 @@ -package io.quarkus.platform.descriptor.tests; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Path; -import java.util.function.Function; - -import org.junit.jupiter.api.Test; - -import io.quarkus.platform.descriptor.loader.json.ArtifactResolver; -import io.quarkus.platform.descriptor.loader.json.QuarkusJsonPlatformDescriptorLoader; -import io.quarkus.platform.descriptor.loader.json.QuarkusJsonPlatformDescriptorLoaderContext; -import io.quarkus.platform.descriptor.loader.json.impl.QuarkusJsonPlatformDescriptor; -import io.quarkus.platform.descriptor.loader.json.impl.QuarkusJsonPlatformDescriptorLoaderImpl; - -class PlatformDescriptorLoaderTest { - - @Test - void test() { - - QuarkusJsonPlatformDescriptorLoader<QuarkusJsonPlatformDescriptor> qpd = new QuarkusJsonPlatformDescriptorLoaderImpl(); - - final ArtifactResolver artifactResolver = new ArtifactResolver() { - - @Override - public <T> T process(String groupId, String artifactId, String classifier, String type, String version, - Function<Path, T> processor) { - throw new UnsupportedOperationException(); - } - }; - - QuarkusJsonPlatformDescriptorLoaderContext context = new QuarkusJsonPlatformDescriptorLoaderContext(artifactResolver) { - @Override - public <T> T parseJson(Function<InputStream, T> parser) { - String resourceName = "fakeextensions.json"; - - final InputStream is = getClass().getClassLoader().getResourceAsStream(resourceName); - if (is == null) { - throw new IllegalStateException("Failed to locate " + resourceName + " on the classpath"); - } - - try { - return parser.apply(is); - } finally { - try { - is.close(); - } catch (IOException e) { - } - } - } - - }; - - QuarkusJsonPlatformDescriptor load = qpd.load(context); - assertNotNull(load); - assertEquals(85, load.getExtensions().size()); - assertEquals(1, load.getCategories().size()); - assertThat(load.getMetadata()).containsKeys("application-properties", "maven", "gradle"); - } - -} diff --git a/devtools/platform-descriptor-json/src/test/resources/fakeextensions.json b/devtools/platform-descriptor-json/src/test/resources/fakeextensions.json deleted file mode 100644 index 5726a1feba9944..00000000000000 --- a/devtools/platform-descriptor-json/src/test/resources/fakeextensions.json +++ /dev/null @@ -1,1249 +0,0 @@ - -{ - "any-future-property" : "blah", - "metadata":{ - "application-properties": { - "quarkus.native.builder-image" : "foo-bar" - }, - "maven" : { - "repositories" : [ - { - "id": "redhat", - "url": "https://maven.repository.redhat.com", - "releases-enabled": "true", - "snapshots-enabled": "false" - } - ], - "plugin-repositories" : [ - { - "id": "redhat", - "url": "https://maven.repository.redhat.com", - "releases-enabled": "true", - "snapshots-enabled": "false" - } - ] - }, - "gradle" : { - "repositories" : [ - { - "id": "redhat", - "url": "https://maven.repository.redhat.com" - } - ] - } - }, - "bom": { - "group-id": "io.quarkus", - "artifact-id": "quarkus-bom", - "version": "999-SNAPSHOT" - }, - - "categories": [ - { - "name" : "Web", - "id" : "web", - "description": "web is webby", - "metadata": { - "pinned": [ - "x.y.z", - "1.2.3" - ] - } - } - ], - - "extensions": [ - { - "name": "Quarkus - Core", - "metadata": { - "keywords": [ - ] - }, - "short-name": "wonka", - "group-id": "io.quarkus", - "artifact-id": "quarkus-core", - "version": "999-SNAPSHOT", - "description": "Build parent to bring in required dependencies" - }, - { - "name": "ArC", - "short-name": "CDI", - "guide": "https://quarkus.io/guides/cdi-reference", - "metadata": { - "keywords": [ - "arc", - "cdi", - "dependency-injection", - "di" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-arc", - "version": "999-SNAPSHOT", - "description": "Build time CDI dependency injection" - }, - { - "metadata": { - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-caffeine", - "version": "999-SNAPSHOT", - "name": "Quarkus - Caffeine - Runtime", - "description": "A high performance caching library for Java 8+" - }, - { - "metadata": { - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-jaxb", - "version": "999-SNAPSHOT", - "name": "Quarkus - JAXB - Runtime", - "description": "XML serialization support" - }, - { - "name": "Jackson", - "metadata": { - "keywords": [ - "jackson", - "json" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-jackson", - "version": "999-SNAPSHOT", - "description": "Jackson Databind support" - }, - { - "name": "JSON-B", - "guide": "https://quarkus.io/guides/rest-json", - "metadata": { - "keywords": [ - "jsonb", - "json-b", - "json" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-jsonb", - "version": "999-SNAPSHOT", - "description": "JSON Binding support" - }, - { - "name": "JSON-P", - "metadata": { - "keywords": [ - "jsonp", - "json-p", - "json" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-jsonp", - "version": "999-SNAPSHOT", - "description": "JSON Processing support" - }, - { - "metadata": { - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-netty", - "version": "999-SNAPSHOT", - "name": "Quarkus - Netty - Runtime", - "description": "Netty is a non-blocking I/O client-server framework. Used by Quarkus as foundation layer." - }, - { - "name": "Agroal - Database connection pool", - "metadata": { - "keywords": [ - "agroal", - "database-connection-pool" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-agroal", - "version": "999-SNAPSHOT", - "description": "Pool your database connections (included in Hibernate ORM)" - }, - { - "name": "Artemis Core", - "metadata": { - "keywords": [ - "artemis-core", - "artemis" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-artemis-core", - "version": "999-SNAPSHOT", - "description": "Use ActiveMQ Artemis as message broker" - }, - { - "name": "Artemis JMS", - "metadata": { - "keywords": [ - "artemis-jms", - "artemis" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-artemis-jms", - "version": "999-SNAPSHOT", - "description": "Use ActiveMQ Artemis as a JMS implementation" - }, - { - "metadata": { - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-elasticsearch-rest-client", - "version": "999-SNAPSHOT", - "name": "Quarkus - Elasticsearch REST client - Runtime", - "description": "Elasticsearch REST client" - }, - { - "name": "Jaeger", - "metadata": { - "keywords": [ - "jaeger" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-security", - "version": "999-SNAPSHOT", - "description": "Security" - }, - { - "metadata": { - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-elytron-security", - "version": "999-SNAPSHOT", - "name": "Quarkus - Elytron Security - Runtime", - "description": "Secure your services" - }, - { - "name": "Properties File based Security", - "guide": "https://quarkus.io/guides/security-properties", - "metadata": { - "keywords": [ - "security" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-elytron-security-properties-file", - "version": "999-SNAPSHOT", - "description": "Secure your applications using properties files" - }, - { - "name": "Elytron Security OAuth 2.0", - "metadata": { - "keywords": [ - "security", - "oauth2" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-elytron-security-oauth2", - "version": "999-SNAPSHOT", - "description": "Secure your applications with OAuth2 opaque tokens" - }, - { - "name": "OpenID Connect", - "guide": "https://quarkus.io/guides/security-openid-connect", - "metadata": { - "keywords": [ - "oauth2", - "openid-connect" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-oidc", - "version": "999-SNAPSHOT", - "description": "Secure your applications with OpenID Connect and Keycloak" - }, - { - "name": "Flyway", - "guide": "https://quarkus.io/guides/flyway", - "metadata": { - "keywords": [ - "flyway", - "database", - "data" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-flyway", - "version": "999-SNAPSHOT", - "description": "Handle your database schema migrations" - }, - { - "name": "Hibernate ORM", - "short-name": "JPA", - "guide": "https://quarkus.io/guides/hibernate-orm", - "metadata": { - "keywords": [ - "hibernate-orm", - "jpa", - "hibernate" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-hibernate-orm", - "version": "999-SNAPSHOT", - "description": "Define your persistent model with Hibernate ORM and JPA" - }, - { - "name": "Hibernate ORM with Panache", - "guide": "https://quarkus.io/guides/hibernate-orm-panache", - "metadata": { - "keywords": [ - "hibernate-orm-panache", - "panache", - "hibernate", - "jpa" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-hibernate-orm-panache", - "version": "999-SNAPSHOT", - "description": "Define your persistent model in Hibernate ORM with Panache" - }, - { - "name": "MongoDB with Panache", - "metadata": { - "keywords": [ - "mongo", - "mongodb", - "nosql", - "datastore", - "panache" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-mongodb-panache", - "version": "999-SNAPSHOT", - "description": "Use an active record or repository pattern with MongoDB" - }, - { - "name": "Hibernate Search + Elasticsearch", - "guide": "https://quarkus.io/guides/hibernate-search-orm-elasticsearch", - "metadata": { - "keywords": [ - "hibernate-search-elasticsearch", - "search", - "full-text", - "hibernate", - "elasticsearch" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-hibernate-search-orm-elasticsearch", - "version": "999-SNAPSHOT", - "description": "Automatically index your Hibernate entities in Elasticsearch" - }, - { - "name": "Hibernate Validator", - "short-name": "bean validation", - "guide": "https://quarkus.io/guides/validation", - "metadata": { - "keywords": [ - "hibernate-validator", - "bean-validation", - "validation" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-hibernate-validator", - "version": "999-SNAPSHOT", - "description": "Validate data coming to your REST endpoints" - }, - { - "name": "Infinispan Client", - "guide": "https://quarkus.io/guides/infinispan-client", - "metadata": { - "keywords": [ - "infinispan-client", - "data-grid-client", - "infinispan" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-infinispan-client", - "version": "999-SNAPSHOT", - "description": "Connect to the Infinispan data grid for distributed caching" - }, - { - "name": "Infinispan Embedded", - "metadata": { - "keywords": [ - "infinispan" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-infinispan-embedded", - "version": "999-SNAPSHOT", - "description": "Run an embedded Infinispan data grid server for distributed caching" - }, - { - "name": "Security", - "metadata": { - "keywords": [ - "security" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-jaeger", - "version": "999-SNAPSHOT", - "description": "Trace your services with Jaeger" - }, - { - "name": "JDBC Driver - PostgreSQL", - "metadata": { - "keywords": [ - "jdbc-postgresql", - "jdbc", - "postgresql" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-jdbc-postgresql", - "version": "999-SNAPSHOT", - "description": "PostgreSQL database connector" - }, - { - "name": "JDBC Driver - H2", - "metadata": { - "keywords": [ - "jdbc-h2", - "jdbc", - "h2" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-jdbc-h2", - "version": "999-SNAPSHOT", - "description": "H2 database connector" - }, - { - "name": "JDBC Driver - MariaDB", - "metadata": { - "keywords": [ - "jdbc-mariadb", - "jdbc", - "mariadb" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-jdbc-mariadb", - "version": "999-SNAPSHOT", - "description": "MariaDB database connector" - }, - { - "name": "JDBC Driver - Microsoft SQL Server", - "metadata": { - "keywords": [ - "jdbc-mssql", - "jdbc", - "mssql", - "sql-server" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-jdbc-mssql", - "version": "999-SNAPSHOT", - "description": "Microsoft SQL Server database connector" - }, - { - "name": "JDBC Driver - MySQL", - "metadata": { - "keywords": [ - "jdbc-mysql", - "jdbc", - "mysql" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-jdbc-mysql", - "version": "999-SNAPSHOT", - "description": "MySQL database connector" - }, - { - "metadata": { - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-jdbc-derby", - "version": "999-SNAPSHOT", - "name": "Quarkus - JDBC - Derby - Runtime", - "description": "Derby database connector" - }, - { - "name": "Apache Kafka Client", - "metadata": { - "keywords": [ - "kafka" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-kafka-client", - "version": "999-SNAPSHOT", - "description": "A client for Apache Kafka" - }, - { - "name": "Apache Kafka Streams", - "metadata": { - "keywords": [ - "kafka", - "kafka-streams" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-kafka-streams", - "version": "999-SNAPSHOT", - "description": "Implement stream processing applications based on Apache Kafka" - }, - { - "name": "SmallRye Health", - "short-name": "health", - "guide": "https://quarkus.io/guides/microprofile-health", - "metadata": { - "keywords": [ - "smallrye-health", - "health-check", - "health", - "microprofile-health", - "microprofile-health-check" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-smallrye-health", - "version": "999-SNAPSHOT", - "description": "Monitor service health" - }, - { - "name": "SmallRye JWT", - "guide": "https://quarkus.io/guides/security-jwt", - "metadata": { - "keywords": [ - "smallrye-jwt", - "jwt", - "json-web-token", - "rbac" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-smallrye-jwt", - "version": "999-SNAPSHOT", - "description": "Secure your applications with JSON Web Token" - }, - { - "name": "SmallRye Context Propagation", - "short-name": "context propagation", - "metadata": { - "keywords": [ - "smallrye-context-propagation", - "microprofile-context-propagation", - "context-propagation", - "context", - "reactive" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-smallrye-context-propagation", - "version": "999-SNAPSHOT", - "description": "SmallRye Context Propagation" - }, - { - "name": "SmallRye Reactive Streams Operators", - "short-name": "reactive streams", - "metadata": { - "keywords": [ - "smallrye-reactive-streams-operators", - "smallrye-reactive-streams", - "reactive-streams-operators", - "reactive-streams", - "microprofile-reactive-streams", - "reactive" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-smallrye-reactive-streams-operators", - "version": "999-SNAPSHOT", - "description": "Operators for Reactive Streams programming" - }, - { - "name": "SmallRye Reactive Type Converters", - "metadata": { - "keywords": [ - "smallrye-reactive-type-converters", - "reactive-type-converters", - "reactive-streams-operators", - "reactive-streams", - "microprofile-reactive-streams", - "reactive" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-smallrye-reactive-type-converters", - "version": "999-SNAPSHOT", - "description": "Converters for reactive types from various reactive programming libraries" - }, - { - "name": "SmallRye Reactive Messaging", - "guide": "https://quarkus.io/guides/reactive-messaging", - "metadata": { - "keywords": [ - "smallrye-reactive-messaging", - "reactive-messaging", - "reactive" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-smallrye-reactive-messaging", - "version": "999-SNAPSHOT", - "description": "Asynchronous messaging for Reactive Streams" - }, - { - "name": "SmallRye Reactive Messaging - Kafka Connector", - "short-name": "kafka", - "guide": "https://quarkus.io/guides/kafka", - "metadata": { - "keywords": [ - "kafka", - "reactive-kafka" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-smallrye-reactive-messaging-kafka", - "version": "999-SNAPSHOT", - "description": "Kafka reactive messaging connector" - }, - { - "name": "SmallRye Reactive Messaging - AMQP Connector", - "guide": "https://quarkus.io/guides/amqp", - "metadata": { - "keywords": [ - "amqp", - "reactive-amqp" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-smallrye-reactive-messaging-amqp", - "version": "999-SNAPSHOT", - "description": "AMQP reactive messaging connector" - }, - { - "name": "SmallRye Reactive Messaging - MQTT Connector", - "metadata": { - "keywords": [ - "mqtt", - "reactive-mqtt" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-smallrye-reactive-messaging-mqtt", - "version": "999-SNAPSHOT", - "description": "MQTT reactive messaging connector" - }, - { - "name": "SmallRye Metrics", - "short-name": "metrics", - "guide": "https://quarkus.io/guides/microprofile-metrics", - "metadata": { - "keywords": [ - "smallrye-metrics", - "metrics", - "metric", - "prometheus", - "monitoring" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-smallrye-metrics", - "version": "999-SNAPSHOT", - "description": "Extract metrics out of your services" - }, - { - "name": "SmallRye OpenAPI", - "guide": "https://quarkus.io/guides/openapi-swaggerui", - "metadata": { - "keywords": [ - "smallrye-openapi", - "openapi", - "open-api" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-smallrye-openapi", - "version": "999-SNAPSHOT", - "description": "Document your REST APIs with OpenAPI - comes with Swagger UI" - }, - { - "name": "SmallRye OpenTracing", - "guide": "https://quarkus.io/guides/opentracing", - "metadata": { - "keywords": [ - "smallrye-opentracing", - "opentracing", - "tracing", - "distributed-tracing", - "jaeger" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-smallrye-opentracing", - "version": "999-SNAPSHOT", - "description": "Trace your services with Jaeger" - }, - { - "name": "REST Client", - "guide": "https://quarkus.io/guides/rest-client", - "metadata": { - "keywords": [ - "rest-client", - "web-client", - "microprofile-rest-client" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-rest-client", - "version": "999-SNAPSHOT", - "description": "Call REST services" - }, - { - "metadata": { - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-resteasy-common", - "version": "999-SNAPSHOT", - "name": "Quarkus - RESTEasy - Common - Runtime", - "description": "REST framework implementing JAX-RS and more" - }, - { - "name": "RESTEasy JAX-RS", - "short-name": "jax-rs", - "guide": "https://quarkus.io/guides/rest-json", - "metadata": { - "keywords": [ - "resteasy", - "jaxrs", - "web", - "rest" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-resteasy", - "version": "999-SNAPSHOT", - "description": "REST framework implementing JAX-RS and more" - }, - { - "name": "RESTEasy Jackson", - "metadata": { - "keywords": [ - "resteasy-jackson", - "jaxrs-json", - "resteasy-json", - "resteasy", - "jaxrs", - "json", - "jackson" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-resteasy-jackson", - "version": "999-SNAPSHOT", - "description": "Jackson serialization support for RESTEasy" - }, - { - "name": "RESTEasy JSON-B", - "guide": "https://quarkus.io/guides/rest-json", - "metadata": { - "keywords": [ - "resteasy-jsonb", - "jaxrs-json", - "resteasy-json", - "resteasy", - "jaxrs", - "json", - "jsonb" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-resteasy-jsonb", - "version": "999-SNAPSHOT", - "description": "JSON-B serialization support for RESTEasy" - }, - { - "metadata": { - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-resteasy-jaxb", - "version": "999-SNAPSHOT", - "name": "Quarkus - RESTEasy - JAXB - Runtime", - "description": "XML serialization support for RESTEasy" - }, - { - "metadata": { - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-resteasy-server-common", - "version": "999-SNAPSHOT", - "name": "Quarkus - RESTEasy - Server common - Runtime", - "description": "RESTEasy Server common" - }, - { - "name": "Narayana JTA - Transaction manager", - "guide": "https://quarkus.io/guides/transaction", - "metadata": { - "keywords": [ - "narayana-jta", - "narayana", - "jta", - "transactions", - "transaction", - "tx", - "txs" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-narayana-jta", - "version": "999-SNAPSHOT", - "description": "JTA transaction support (included in Hibernate ORM)" - }, - { - "name": "Undertow Servlet", - "short-name": "servlet", - "metadata": { - "keywords": [ - "undertow", - "servlet" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-undertow", - "version": "999-SNAPSHOT", - "description": "Support for servlets" - }, - { - "name": "SmallRye Fault Tolerance", - "metadata": { - "keywords": [ - "smallrye-fault-tolerance", - "fault-tolerance", - "microprofile-fault-tolerance", - "circuit-breaker", - "bulkhead" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-smallrye-fault-tolerance", - "version": "999-SNAPSHOT", - "description": "Define fault-tolerant services" - }, - { - "name": "Eclipse Vert.x - Core", - "metadata": { - "keywords": [ - "eclipse-vert.x", - "vertx", - "vert.x", - "reactive" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-vertx-core", - "version": "999-SNAPSHOT", - "description": "Vert.x Core" - }, - { - "name": "Eclipse Vert.x", - "guide": "https://quarkus.io/guides/vertx", - "metadata": { - "keywords": [ - "eclipse-vert.x", - "vertx", - "vert.x", - "reactive" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-vertx", - "version": "999-SNAPSHOT", - "description": "Reactive application toolkit" - }, - { - "name": "Eclipse Vert.x - HTTP", - "metadata": { - "keywords": [ - "eclipse-vert.x", - "vertx", - "vert.x", - "reactive", - "vertx-http" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-vertx-http", - "version": "999-SNAPSHOT", - "description": "Vert.x HTTP" - }, - { - "metadata": { - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-vertx-web", - "version": "999-SNAPSHOT", - "name": "Quarkus - Vert.x Web - Runtime", - "description": "Vert.x Web" - }, - { - "name": "Reactive PostgreSQL client", - "metadata": { - "keywords": [ - "eclipse-vert.x", - "vertx", - "vert.x", - "reactive", - "database", - "data", - "postgresql" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-reactive-pg-client", - "version": "999-SNAPSHOT", - "description": "A reactive client for the PostgreSQL database" - }, - { - "name": "Reactive MySQL client", - "metadata": { - "keywords": [ - "eclipse-vert.x", - "vertx", - "vert.x", - "reactive", - "database", - "data", - "mysql" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-reactive-mysql-client", - "version": "999-SNAPSHOT", - "description": "A reactive client for the MySQL database" - }, - { - "name": "Mailer", - "guide": "https://quarkus.io/guides/mailer", - "metadata": { - "keywords": [ - "mail", - "mailer" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-mailer", - "version": "999-SNAPSHOT", - "description": "Send emails" - }, - { - "name": "MongoDB client", - "metadata": { - "keywords": [ - "mongo", - "mongodb", - "nosql", - "datastore" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-mongodb-client", - "version": "999-SNAPSHOT", - "description": "An imperative and reactive client for MongoDB" - }, - { - "name": "WebSockets", - "short-name": "websockets", - "guide": "https://quarkus.io/guides/websockets", - "metadata": { - "keywords": [ - "undertow-websockets", - "undertow-websocket", - "websocket", - "websockets", - "web-socket", - "web-sockets" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-websockets", - "version": "999-SNAPSHOT", - "description": "WebSocket support" - }, - { - "name": "Scheduler - tasks", - "guide": "https://quarkus.io/guides/scheduler", - "metadata": { - "keywords": [ - "scheduler", - "tasks", - "periodic-tasks" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-scheduler", - "version": "999-SNAPSHOT", - "description": "Schedule jobs and tasks" - }, - { - "name": "Quarkus Extension for Spring DI API", - "guide": "https://quarkus.io/guides/spring-di", - "metadata": { - "keywords": [ - "spring-di" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-spring-di", - "version": "999-SNAPSHOT", - "description": "Define your dependency injection with Spring DI" - }, - { - "name": "Quarkus Extension for Spring Web API", - "guide": "https://quarkus.io/guides/spring-web", - "metadata": { - "keywords": [ - "spring-web" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-spring-web", - "version": "999-SNAPSHOT", - "description": "Use Spring Web annotations to create your REST services" - }, - { - "name": "Quarkus Extension for Spring Data JPA API", - "guide": "https://quarkus.io/guides/spring-data-jpa", - "metadata": { - "keywords": [ - "spring-data" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-spring-data-jpa", - "version": "999-SNAPSHOT", - "description": "Use Spring Data JPA annotations to create your data access layer" - }, - { - "name": "Swagger UI", - "guide": "https://quarkus.io/guides/openapi-swaggerui", - "metadata": { - "keywords": [ - "swagger-ui" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-swagger-ui", - "version": "999-SNAPSHOT", - "description": "Swagger UI" - }, - { - "name": "Kotlin", - "guide": "https://quarkus.io/guides/kotlin", - "metadata": { - "keywords": [ - "kotlin" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-kotlin", - "version": "999-SNAPSHOT", - "description": "Write your services in Kotlin" - }, - { - "name": "AWS Lambda", - "metadata": { - "keywords": [ - "lambda", - "aws", - "amazon" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-amazon-lambda", - "version": "999-SNAPSHOT", - "description": "AWS Lambda support" - }, - { - "metadata": { - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-amazon-lambda-http", - "version": "999-SNAPSHOT", - "name": "Quarkus - Amazon Lambda HTTP - Runtime", - "description": "Allows Java applications written for a servlet container to run in AWS Lambda" - }, - { - "name": "Amazon DynamoDB client", - "metadata": { - "keywords": [ - "dynamodb", - "dynamo", - "aws", - "amazon" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-amazon-dynamodb", - "version": "999-SNAPSHOT", - "description": "A client for the Amazon DynamoDB datastore" - }, - { - "metadata": { - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-azure-functions-http", - "version": "999-SNAPSHOT", - "name": "Quarkus - HTTP Azure Functions - Runtime", - "description": "This package contains all Java interfaces and annotations to interact with Microsoft Azure functions runtime." - }, - { - "name": "Kubernetes", - "guide": "https://quarkus.io/guides/kubernetes", - "metadata": { - "keywords": [ - "kubernetes" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-kubernetes", - "version": "999-SNAPSHOT", - "description": "Generate Kubernetes resources from annotations" - }, - { - "name": "Kubernetes Client", - "metadata": { - "keywords": [ - "kubernetes-client" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-kubernetes-client", - "version": "999-SNAPSHOT", - "description": "Interact with Kubernetes and develop Kubernetes Operators" - }, - { - "name": "Kogito", - "guide": "https://quarkus.io/guides/kogito", - "metadata": { - "keywords": [ - "kogito", - "drools", - "jbpm" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-kogito", - "version": "999-SNAPSHOT", - "description": "Add business automation capabilities with Kogito" - }, - { - "name": "Apache Tika", - "metadata": { - "keywords": [ - "tika", - "parser" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-tika", - "version": "999-SNAPSHOT", - "description": "Extract data from your documents with Apache Tika" - }, - { - "name": "Neo4j client", - "metadata": { - "keywords": [ - "neo4j", - "graph", - "nosql", - "datastore" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-neo4j", - "version": "999-SNAPSHOT", - "description": "A client for the Neo4j graph datastore" - }, - { - "name": "Scala", - "metadata": { - "keywords": [ - "scala" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-scala", - "version": "999-SNAPSHOT", - "description": "Write your services in Scala" - }, - { - "name": "JGit", - "metadata": { - "keywords": [ - "git" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-jgit", - "version": "999-SNAPSHOT", - "description": "Access your Git repositories" - }, - { - "name": "Narayana STM - Software Transactional Memory", - "guide": "https://quarkus.io/guides/software-transactional-memory", - "metadata": { - "keywords": [ - "narayana-stm", - "narayana", - "stm", - "transactions", - "transaction", - "software-transactional-memory", - "tx", - "txs" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-narayana-stm", - "version": "999-SNAPSHOT", - "description": "Software Transactional Memory (stm) support" - }, - { - "name": "Elytron Security JDBC Realm", - "guide": "https://quarkus.io/guides/security-jdbc", - "metadata": { - "keywords": [ - "security", - "jdbc" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-elytron-security-jdbc", - "version": "999-SNAPSHOT", - "description": "Secure your applications with username/password stored in a database" - }, - { - "name": "Vault", - "guide": "https://quarkus.io/guides/vault", - "metadata": { - "keywords": [ - "vault", - "security" - ] - }, - "group-id": "io.quarkus", - "artifact-id": "quarkus-vault", - "version": "999-SNAPSHOT", - "description": "Store your credentials securely in HashiCorp Vault" - } - ] -} diff --git a/docs/pom.xml b/docs/pom.xml index 6624a9ccb0c768..b5ff6cb6492c1a 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -38,8 +38,12 @@ </dependency> <dependency> <groupId>io.quarkus</groupId> - <artifactId>quarkus-bootstrap-core</artifactId> + <artifactId>quarkus-devtools-registry-client</artifactId> <version>${project.version}</version> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-bootstrap-core</artifactId> <exclusions> <exclusion> <groupId>org.slf4j</groupId> diff --git a/docs/src/main/java/io/quarkus/docs/generation/AllConfigGenerator.java b/docs/src/main/java/io/quarkus/docs/generation/AllConfigGenerator.java index 264bfa90b81ac0..5fb7b4c9996041 100644 --- a/docs/src/main/java/io/quarkus/docs/generation/AllConfigGenerator.java +++ b/docs/src/main/java/io/quarkus/docs/generation/AllConfigGenerator.java @@ -21,11 +21,6 @@ import org.eclipse.aether.resolution.ArtifactRequest; import org.eclipse.aether.resolution.ArtifactResult; -import com.fasterxml.jackson.core.json.JsonReadFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.PropertyNamingStrategies; -import com.fasterxml.jackson.databind.json.JsonMapper; - import io.quarkus.annotation.processor.generate_doc.ConfigDocGeneratedOutput; import io.quarkus.annotation.processor.generate_doc.ConfigDocItem; import io.quarkus.annotation.processor.generate_doc.ConfigDocItemScanner; @@ -34,9 +29,18 @@ import io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; -import io.quarkus.docs.generation.ExtensionJson.Extension; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.catalog.Extension; +import io.quarkus.registry.catalog.json.JsonCatalogMapperHelper; +import io.quarkus.registry.catalog.json.JsonExtensionCatalog; public class AllConfigGenerator { + + public static Artifact toAetherArtifact(ArtifactCoords coords) { + return new DefaultArtifact(coords.getGroupId(), coords.getArtifactId(), coords.getClassifier(), coords.getType(), + coords.getVersion()); + } + public static void main(String[] args) throws BootstrapMavenException, IOException { if (args.length != 2) { // exit 1 will break Maven @@ -52,31 +56,26 @@ public static void main(String[] args) throws BootstrapMavenException, IOExcepti // exit 0 will break Maven return; } - ObjectMapper mapper = JsonMapper.builder() - .enable(JsonReadFeature.ALLOW_JAVA_COMMENTS) - .enable(JsonReadFeature.ALLOW_LEADING_ZEROS_FOR_NUMBERS) - .propertyNamingStrategy(PropertyNamingStrategies.KEBAB_CASE) - .build(); MavenArtifactResolver resolver = MavenArtifactResolver.builder().setWorkspaceDiscovery(false).build(); - // let's read it (and ignore the fields we don't need) - ExtensionJson extensionJson = mapper.readValue(jsonFile, ExtensionJson.class); + final JsonExtensionCatalog extensionJson = JsonCatalogMapperHelper.deserialize(jsonFile.toPath(), + JsonExtensionCatalog.class); // now get all the listed extension jars via Maven - List<ArtifactRequest> requests = new ArrayList<>(extensionJson.extensions.size()); + List<ArtifactRequest> requests = new ArrayList<>(extensionJson.getExtensions().size()); Map<String, Extension> extensionsByGav = new HashMap<>(); Map<String, Extension> extensionsByConfigRoots = new HashMap<>(); - for (Extension extension : extensionJson.extensions) { + for (Extension extension : extensionJson.getExtensions()) { ArtifactRequest request = new ArtifactRequest(); - Artifact artifact = new DefaultArtifact(extension.groupId, extension.artifactId, "jar", version); + Artifact artifact = toAetherArtifact(extension.getArtifact()); request.setArtifact(artifact); requests.add(request); // record the extension for this GAV - extensionsByGav.put(extension.groupId + ":" + extension.artifactId, extension); + extensionsByGav.put(artifact.getGroupId() + ":" + artifact.getArtifactId(), extension); } // examine all the extension jars - List<ArtifactRequest> deploymentRequests = new ArrayList<>(extensionJson.extensions.size()); + List<ArtifactRequest> deploymentRequests = new ArrayList<>(extensionJson.getExtensions().size()); for (ArtifactResult result : resolver.resolve(requests)) { Artifact artifact = result.getArtifact(); // which extension was this for? @@ -140,17 +139,18 @@ public static void main(String[] args) throws BootstrapMavenException, IOExcepti for (Entry<String, Extension> entry : extensionsByConfigRoots.entrySet()) { List<ConfigDocItem> items = docItemsByConfigRoots.get(entry.getKey()); if (items != null) { - String extensionName = entry.getValue().name; + String extensionName = entry.getValue().getName(); if (extensionName == null) { - String extensionGav = entry.getValue().groupId + ":" + entry.getValue().artifactId; // compute the docs file name for this extension String docFileName = DocGeneratorUtil.computeExtensionDocFileName(entry.getKey()); // now approximate an extension file name based on it extensionName = guessExtensionNameFromDocumentationFileName(docFileName); - System.err.println("WARNING: Extension name missing for " + extensionGav + " using guessed extension name: " - + extensionName); + System.err.println("WARNING: Extension name missing for " + + (entry.getValue().getArtifact().getGroupId() + ":" + + entry.getValue().getArtifact().getArtifactId()) + + " using guessed extension name: " + extensionName); } - artifactIdsByName.put(extensionName, entry.getValue().artifactId); + artifactIdsByName.put(extensionName, entry.getValue().getArtifact().getArtifactId()); List<ConfigDocItem> existingConfigDocItems = sortedConfigItemsByExtension.get(extensionName); if (existingConfigDocItems != null) { DocGeneratorUtil.appendConfigItemsIntoExistingOnes(existingConfigDocItems, items); diff --git a/docs/src/main/java/io/quarkus/docs/generation/ExtensionJson.java b/docs/src/main/java/io/quarkus/docs/generation/ExtensionJson.java deleted file mode 100644 index c81ae589119246..00000000000000 --- a/docs/src/main/java/io/quarkus/docs/generation/ExtensionJson.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.quarkus.docs.generation; - -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class ExtensionJson { - public List<Extension> extensions; - - @JsonIgnoreProperties(ignoreUnknown = true) - public static class Extension { - public String name, groupId, artifactId; - } -} \ No newline at end of file diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/AppArtifact.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/AppArtifact.java index 54065a7b2b4ce1..264ebd9ec2b692 100644 --- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/AppArtifact.java +++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/AppArtifact.java @@ -12,6 +12,10 @@ public class AppArtifact extends AppArtifactCoords implements Serializable { protected PathsCollection paths; + public AppArtifact(AppArtifactCoords coords) { + this(coords.getGroupId(), coords.getArtifactId(), coords.getClassifier(), coords.getType(), coords.getVersion()); + } + public AppArtifact(String groupId, String artifactId, String version) { super(groupId, artifactId, version); } diff --git a/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/ResolverSetupCleanup.java b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/ResolverSetupCleanup.java index 0c0ce539333513..ca5ed97db15397 100644 --- a/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/ResolverSetupCleanup.java +++ b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/ResolverSetupCleanup.java @@ -58,7 +58,7 @@ protected boolean cleanWorkDir() { protected BootstrapAppModelResolver initResolver(LocalProject currentProject) throws Exception { return new BootstrapAppModelResolver(MavenArtifactResolver.builder() - .setRepoHome(repoHome) + .setLocalRepository(repoHome.toString()) .setOffline(true) .setWorkspaceDiscovery(false) .setCurrentProject(currentProject) diff --git a/independent-projects/bootstrap/maven-plugin/src/test/java/io/quarkus/maven/TreeMojoTestBase.java b/independent-projects/bootstrap/maven-plugin/src/test/java/io/quarkus/maven/TreeMojoTestBase.java index 30d5d5fd120a26..fcf9969458c85a 100644 --- a/independent-projects/bootstrap/maven-plugin/src/test/java/io/quarkus/maven/TreeMojoTestBase.java +++ b/independent-projects/bootstrap/maven-plugin/src/test/java/io/quarkus/maven/TreeMojoTestBase.java @@ -42,7 +42,7 @@ public void setup() throws Exception { mvnResolver = MavenArtifactResolver.builder() .setOffline(true) - .setRepoHome(repoHome) + .setLocalRepository(repoHome.toString()) .setRemoteRepositories(Collections.emptyList()) .build(); diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/MavenArtifactResolver.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/MavenArtifactResolver.java index 911ae10d745bd0..4a2e108a3cf95c 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/MavenArtifactResolver.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/MavenArtifactResolver.java @@ -4,6 +4,8 @@ package io.quarkus.bootstrap.resolver.maven; import io.quarkus.bootstrap.model.AppArtifactKey; +import io.quarkus.bootstrap.resolver.AppModelResolverException; +import io.quarkus.bootstrap.util.PropertyUtils; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -19,6 +21,7 @@ import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.collection.CollectRequest; import org.eclipse.aether.collection.CollectResult; import org.eclipse.aether.collection.DependencyCollectionException; @@ -28,7 +31,6 @@ import org.eclipse.aether.impl.RemoteRepositoryManager; import org.eclipse.aether.installation.InstallRequest; import org.eclipse.aether.installation.InstallationException; -import org.eclipse.aether.repository.LocalRepository; import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.resolution.ArtifactDescriptorException; import org.eclipse.aether.resolution.ArtifactDescriptorRequest; @@ -45,6 +47,7 @@ import org.eclipse.aether.util.artifact.JavaScopes; import org.eclipse.aether.util.version.GenericVersionScheme; import org.eclipse.aether.version.InvalidVersionSpecificationException; +import org.eclipse.aether.version.Version; /** * @@ -52,36 +55,18 @@ */ public class MavenArtifactResolver { + private static final String SECONDARY_LOCAL_REPO_PROP = "io.quarkus.maven.secondary-local-repo"; + public static class Builder extends BootstrapMavenContextConfig<Builder> { - private boolean reTryFailedResolutionsAgainstDefaultLocalRepo; + private Path secondaryLocalRepo; private Builder() { super(); } - /** - * In case custom local repository location is configured using {@link #setRepoHome(Path)}, - * this method can be used to enable artifact resolutions that failed for the configured - * custom local repository to be re-tried against the default user local repository before - * failing. - * <p> - * NOTE: the default behavior is <b>not</b> to use the default user local repository as the fallback one. - * - * @param value true if the failed resolution requests should be re-tried against the default - * user local repo before failing - * - * @return this builder instance - */ - public Builder setReTryFailedResolutionsAgainstDefaultLocalRepo(boolean value) { - this.reTryFailedResolutionsAgainstDefaultLocalRepo = value; - return this; - } - - public Builder setRepoHome(Path home) { - if (home != null) { - setLocalRepository(home.toString()); - } + public Builder setSecondaryLocalRepo(Path secondaryLocalRepo) { + this.secondaryLocalRepo = secondaryLocalRepo; return this; } @@ -106,10 +91,14 @@ private MavenArtifactResolver(Builder builder) throws BootstrapMavenException { this.repoSystem = context.getRepositorySystem(); final RepositorySystemSession session = context.getRepositorySystemSession(); - if (builder.localRepo != null && builder.reTryFailedResolutionsAgainstDefaultLocalRepo) { + final String secondaryRepo = PropertyUtils.getProperty(SECONDARY_LOCAL_REPO_PROP); + if (secondaryRepo != null) { + builder.secondaryLocalRepo = Paths.get(secondaryRepo); + } + if (builder.secondaryLocalRepo != null) { localRepoManager = new MavenLocalRepositoryManager( - repoSystem.newLocalRepositoryManager(session, new LocalRepository(builder.localRepo)), - Paths.get(context.getLocalRepo())); + session.getLocalRepositoryManager(), + builder.secondaryLocalRepo); this.repoSession = new DefaultRepositorySystemSession(session).setLocalRepositoryManager(localRepoManager); } else { this.repoSession = session; @@ -219,6 +208,26 @@ public VersionRangeResult resolveVersionRange(Artifact artifact) throws Bootstra } } + public String getLatestVersionFromRange(Artifact artifact, String range) throws AppModelResolverException { + return getLatest(resolveVersionRange(new DefaultArtifact(artifact.getGroupId(), artifact.getArtifactId(), + artifact.getClassifier(), artifact.getExtension(), range))); + } + + private String getLatest(final VersionRangeResult rangeResult) { + final List<Version> versions = rangeResult.getVersions(); + if (versions.isEmpty()) { + return null; + } + Version next = versions.get(0); + for (int i = 1; i < versions.size(); ++i) { + final Version candidate = versions.get(i); + if (candidate.compareTo(next) > 0) { + next = candidate; + } + } + return next.toString(); + } + public CollectResult collectDependencies(Artifact artifact, List<Dependency> deps) throws BootstrapMavenException { return collectDependencies(artifact, deps, Collections.emptyList()); } diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/MavenLocalRepositoryManager.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/MavenLocalRepositoryManager.java index b59764b9340ee5..bf1b4ab3f89854 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/MavenLocalRepositoryManager.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/MavenLocalRepositoryManager.java @@ -24,19 +24,13 @@ public class MavenLocalRepositoryManager implements LocalRepositoryManager { private final LocalRepositoryManager delegate; - private final Path userLocalRepo; - private final Path appCreatorRepo; - private final boolean relinkResolvedArtifacts; + private final Path secondaryRepo; + private final Path originalRepo; - public MavenLocalRepositoryManager(LocalRepositoryManager delegate, Path userLocalRepo) { - this(delegate, userLocalRepo, false); - } - - public MavenLocalRepositoryManager(LocalRepositoryManager delegate, Path userLocalRepo, boolean relinkResolvedArtifacts) { + public MavenLocalRepositoryManager(LocalRepositoryManager delegate, Path secondaryRepo) { this.delegate = delegate; - this.userLocalRepo = userLocalRepo; - this.appCreatorRepo = delegate.getRepository().getBasedir().toPath(); - this.relinkResolvedArtifacts = relinkResolvedArtifacts; + this.secondaryRepo = secondaryRepo; + this.originalRepo = delegate.getRepository().getBasedir().toPath(); } @Override @@ -65,7 +59,7 @@ public String getPathForRemoteMetadata(Metadata metadata, RemoteRepository repos } public void relink(String groupId, String artifactId, String classifier, String type, String version, Path p) { - final Path creatorRepoPath = getLocalPath(appCreatorRepo, groupId, artifactId, classifier, type, version); + final Path creatorRepoPath = getLocalPath(originalRepo, groupId, artifactId, classifier, type, version); try { IoUtils.copy(p, creatorRepoPath); } catch (IOException e) { @@ -80,23 +74,12 @@ public LocalArtifactResult find(RepositorySystemSession session, LocalArtifactRe return result; } final Artifact artifact = request.getArtifact(); - final Path userRepoPath = getLocalPath(userLocalRepo, artifact.getGroupId(), artifact.getArtifactId(), + final Path secondaryLocation = getLocalPath(secondaryRepo, artifact.getGroupId(), artifact.getArtifactId(), artifact.getClassifier(), artifact.getExtension(), artifact.getVersion()); - if (!Files.exists(userRepoPath)) { + if (!Files.exists(secondaryLocation)) { return result; } - if (relinkResolvedArtifacts) { - final Path creatorRepoPath = getLocalPath(appCreatorRepo, artifact.getGroupId(), artifact.getArtifactId(), - artifact.getClassifier(), artifact.getExtension(), artifact.getVersion()); - try { - IoUtils.copy(userRepoPath, creatorRepoPath); - } catch (IOException e) { - throw new IllegalStateException("Failed to copy " + userRepoPath + " to a staging repo", e); - } - result.setFile(creatorRepoPath.toFile()); - } else { - result.setFile(userRepoPath.toFile()); - } + result.setFile(secondaryLocation.toFile()); artifact.setFile(result.getFile()); result.setAvailable(true); return result; @@ -114,23 +97,12 @@ public LocalMetadataResult find(RepositorySystemSession session, LocalMetadataRe return result; } final Metadata metadata = request.getMetadata(); - final Path userRepoPath = getMetadataPath(userLocalRepo, metadata.getGroupId(), metadata.getArtifactId(), + final Path userRepoPath = getMetadataPath(secondaryRepo, metadata.getGroupId(), metadata.getArtifactId(), metadata.getType(), metadata.getVersion()); if (!Files.exists(userRepoPath)) { return result; } - if (relinkResolvedArtifacts) { - final Path creatorRepoPath = getMetadataPath(appCreatorRepo, metadata.getGroupId(), metadata.getArtifactId(), - metadata.getType(), metadata.getVersion()); - try { - IoUtils.copy(userRepoPath, creatorRepoPath); - } catch (IOException e) { - throw new IllegalStateException("Failed to copy " + userRepoPath + " to a staging repo", e); - } - result.setFile(creatorRepoPath.toFile()); - } else { - result.setFile(userRepoPath.toFile()); - } + result.setFile(userRepoPath.toFile()); metadata.setFile(result.getFile()); return result; } diff --git a/independent-projects/tools/artifact-api/pom.xml b/independent-projects/tools/artifact-api/pom.xml new file mode 100644 index 00000000000000..0aee54bb768f53 --- /dev/null +++ b/independent-projects/tools/artifact-api/pom.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-tools-parent</artifactId> + <version>999-SNAPSHOT</version> + </parent> + + <artifactId>quarkus-devtools-artifact-api</artifactId> + <name>Quarkus - Dev tools - Maven Artifact API</name> + + <dependencies> + </dependencies> +</project> diff --git a/independent-projects/tools/artifact-api/src/main/java/io/quarkus/maven/ArtifactCoords.java b/independent-projects/tools/artifact-api/src/main/java/io/quarkus/maven/ArtifactCoords.java new file mode 100644 index 00000000000000..529f8a1d256749 --- /dev/null +++ b/independent-projects/tools/artifact-api/src/main/java/io/quarkus/maven/ArtifactCoords.java @@ -0,0 +1,129 @@ +package io.quarkus.maven; + +import java.io.Serializable; +import java.util.Objects; + +public class ArtifactCoords implements Serializable { + + public static final String TYPE_JAR = "jar"; + public static final String TYPE_POM = "pom"; + + public static ArtifactCoords fromString(String str) { + return new ArtifactCoords(split(str, new String[5])); + } + + public static ArtifactCoords pom(String groupId, String artifactId, String version) { + return new ArtifactCoords(groupId, artifactId, null, TYPE_POM, version); + } + + protected static String[] split(String str, String[] parts) { + final int versionSep = str.lastIndexOf(':'); + if (versionSep <= 0 || versionSep == str.length() - 1) { + throw new IllegalArgumentException("One of type, version or separating them ':' is missing from '" + str + "'"); + } + parts[4] = str.substring(versionSep + 1); + ArtifactKey.split(str, parts, versionSep); + return parts; + } + + protected final String groupId; + protected final String artifactId; + protected final String classifier; + protected final String type; + protected final String version; + + protected transient ArtifactKey key; + + protected ArtifactCoords(String[] parts) { + groupId = parts[0]; + artifactId = parts[1]; + classifier = parts[2]; + type = parts[3] == null ? TYPE_JAR : parts[3]; + version = parts[4]; + } + + public ArtifactCoords(ArtifactKey key, String version) { + this.key = key; + this.groupId = key.getGroupId(); + this.artifactId = key.getArtifactId(); + this.classifier = key.getClassifier(); + this.type = key.getType(); + this.version = version; + } + + public ArtifactCoords(String groupId, String artifactId, String version) { + this(groupId, artifactId, "", TYPE_JAR, version); + } + + public ArtifactCoords(String groupId, String artifactId, String type, String version) { + this(groupId, artifactId, "", type, version); + } + + public ArtifactCoords(String groupId, String artifactId, String classifier, String type, String version) { + this.groupId = groupId; + this.artifactId = artifactId; + this.classifier = classifier == null ? "" : classifier; + this.type = type == null ? TYPE_JAR : type; + this.version = version; + } + + public String getGroupId() { + return groupId; + } + + public String getArtifactId() { + return artifactId; + } + + public String getClassifier() { + return classifier; + } + + public String getType() { + return type; + } + + public String getVersion() { + return version; + } + + public ArtifactKey getKey() { + return key == null ? key = new ArtifactKey(groupId, artifactId, classifier, type) : key; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ArtifactCoords that = (ArtifactCoords) o; + return Objects.equals(groupId, that.groupId) && + Objects.equals(artifactId, that.artifactId) && + Objects.equals(classifier, that.classifier) && + Objects.equals(type, that.type) && + Objects.equals(version, that.version); + } + + @Override + public int hashCode() { + return Objects.hash(groupId, artifactId, classifier, type, version); + } + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder(); + append(buf); + return buf.toString(); + } + + protected StringBuilder append(final StringBuilder buf) { + buf.append(groupId).append(':').append(artifactId).append(':'); + if (classifier != null && !classifier.isEmpty()) { + buf.append(classifier); + } + return buf.append(':').append(type).append(':').append(version); + } +} diff --git a/independent-projects/tools/artifact-api/src/main/java/io/quarkus/maven/ArtifactKey.java b/independent-projects/tools/artifact-api/src/main/java/io/quarkus/maven/ArtifactKey.java new file mode 100644 index 00000000000000..7283a1e9388ba1 --- /dev/null +++ b/independent-projects/tools/artifact-api/src/main/java/io/quarkus/maven/ArtifactKey.java @@ -0,0 +1,171 @@ +package io.quarkus.maven; + +import java.io.Serializable; + +public class ArtifactKey implements Serializable { + + public static ArtifactKey fromString(String str) { + return new ArtifactKey(split(str, new String[4], str.length())); + } + + protected static String[] split(String str, String[] parts, int fromIndex) { + int i = str.lastIndexOf(':', fromIndex - 1); + if (i <= 0) { + throw new IllegalArgumentException("GroupId and artifactId separating ':' is absent or not in the right place in '" + + str.substring(0, fromIndex) + "'"); + } + parts[3] = str.substring(i + 1, fromIndex); + fromIndex = i; + i = str.lastIndexOf(':', fromIndex - 1); + if (i < 0) { + parts[0] = str.substring(0, fromIndex); + if ((parts[1] = parts[3]).isEmpty()) { + throw new IllegalArgumentException("ArtifactId is empty in `" + str + "`"); + } + parts[2] = ""; + parts[3] = null; + return parts; + } + if (i == 0) { + throw new IllegalArgumentException( + "One of groupId or artifactId is missing from '" + str.substring(0, fromIndex) + "'"); + } + if (i == fromIndex - 1) { + parts[2] = ""; + } else { + parts[2] = str.substring(i + 1, fromIndex); + } + + fromIndex = i; + i = str.lastIndexOf(':', fromIndex - 1); + if (i < 0) { + parts[0] = str.substring(0, fromIndex); + if ((parts[1] = parts[2]).isEmpty()) { + throw new IllegalArgumentException("ArtifactId is empty in `" + str + "`"); + } + parts[2] = parts[3]; + parts[3] = null; + return parts; + } + if (i == 0 || i == fromIndex - 1) { + throw new IllegalArgumentException( + "One of groupId or artifactId is missing from '" + str.substring(0, fromIndex) + "'"); + } + + parts[0] = str.substring(0, i); + parts[1] = str.substring(i + 1, fromIndex); + if (parts[3].isEmpty()) { + parts[3] = null; + } + return parts; + } + + protected final String groupId; + protected final String artifactId; + protected final String classifier; + protected final String type; + + public ArtifactKey(String[] parts) { + this.groupId = parts[0]; + this.artifactId = parts[1]; + if (parts.length == 2 || parts[2] == null) { + this.classifier = ""; + } else { + this.classifier = parts[2]; + } + if (parts.length <= 3 || parts[3] == null) { + this.type = "jar"; + } else { + this.type = parts[3]; + } + } + + public ArtifactKey(String groupId, String artifactId) { + this(groupId, artifactId, null); + } + + public ArtifactKey(String groupId, String artifactId, String classifier) { + this(groupId, artifactId, classifier, null); + } + + public ArtifactKey(String groupId, String artifactId, String classifier, String type) { + this.groupId = groupId; + this.artifactId = artifactId; + this.classifier = classifier == null ? "" : classifier; + this.type = type; + } + + public String getGroupId() { + return groupId; + } + + public String getArtifactId() { + return artifactId; + } + + public String getClassifier() { + return classifier; + } + + public String getType() { + return type; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((artifactId == null) ? 0 : artifactId.hashCode()); + result = prime * result + ((classifier == null) ? 0 : classifier.hashCode()); + result = prime * result + ((groupId == null) ? 0 : groupId.hashCode()); + result = prime * result + ((type == null) ? 0 : type.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ArtifactKey other = (ArtifactKey) obj; + if (artifactId == null) { + if (other.artifactId != null) + return false; + } else if (!artifactId.equals(other.artifactId)) + return false; + if (classifier == null) { + if (other.classifier != null) + return false; + } else if (!classifier.equals(other.classifier)) + return false; + if (groupId == null) { + if (other.groupId != null) + return false; + } else if (!groupId.equals(other.groupId)) + return false; + if (type == null) { + if (other.type != null) + return false; + } else if (!type.equals(other.type)) + return false; + return true; + } + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder(); + buf.append(groupId).append(':').append(artifactId); + if (!classifier.isEmpty()) { + buf.append(':').append(classifier); + } else if (type != null) { + buf.append(':'); + } + if (type != null) { + buf.append(':').append(type); + } + return buf.toString(); + } +} diff --git a/independent-projects/tools/devtools-common/pom.xml b/independent-projects/tools/devtools-common/pom.xml index 400f63d0b7b355..330f979aaf37d7 100644 --- a/independent-projects/tools/devtools-common/pom.xml +++ b/independent-projects/tools/devtools-common/pom.xml @@ -28,7 +28,7 @@ <dependencies> <dependency> <groupId>io.quarkus</groupId> - <artifactId>quarkus-bootstrap-maven-resolver</artifactId> + <artifactId>quarkus-devtools-registry-client</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> @@ -42,10 +42,6 @@ <groupId>io.quarkus.qute</groupId> <artifactId>qute-generator</artifactId> </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-platform-descriptor-api</artifactId> - </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-compress</artifactId> diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/codestarts/QuarkusPlatformCodestartResourceLoader.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/codestarts/QuarkusPlatformCodestartResourceLoader.java index 48a11a54038d4c..7753ff673ebd11 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/codestarts/QuarkusPlatformCodestartResourceLoader.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/codestarts/QuarkusPlatformCodestartResourceLoader.java @@ -1,21 +1,21 @@ package io.quarkus.devtools.codestarts; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.platform.descriptor.loader.json.ResourceLoader; import java.io.IOException; public final class QuarkusPlatformCodestartResourceLoader implements CodestartPathLoader { - private QuarkusPlatformDescriptor platformDescr; + private ResourceLoader resourceLoader; - private QuarkusPlatformCodestartResourceLoader(QuarkusPlatformDescriptor platformDescr) { - this.platformDescr = platformDescr; + private QuarkusPlatformCodestartResourceLoader(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; } - public static CodestartPathLoader platformPathLoader(QuarkusPlatformDescriptor platformDescr) { - return new QuarkusPlatformCodestartResourceLoader(platformDescr); + public static CodestartPathLoader platformPathLoader(ResourceLoader resourceLoader) { + return new QuarkusPlatformCodestartResourceLoader(resourceLoader); } @Override public <T> T loadResourceAsPath(String name, PathConsumer<T> consumer) throws IOException { - return platformDescr.loadResourceAsPath(name, consumer::consume); + return resourceLoader.loadResourceAsPath(name, consumer::consume); } } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/codestarts/jbang/QuarkusJBangCodestartCatalog.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/codestarts/jbang/QuarkusJBangCodestartCatalog.java index 9739d1e5438751..29e91350b5a50c 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/codestarts/jbang/QuarkusJBangCodestartCatalog.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/codestarts/jbang/QuarkusJBangCodestartCatalog.java @@ -7,7 +7,7 @@ import io.quarkus.devtools.codestarts.CodestartPathLoader; import io.quarkus.devtools.codestarts.DataKey; import io.quarkus.devtools.codestarts.core.GenericCodestartCatalog; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.platform.descriptor.loader.json.ResourceLoader; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; @@ -47,9 +47,9 @@ private QuarkusJBangCodestartCatalog(Collection<Codestart> codestarts) { super(codestarts); } - public static QuarkusJBangCodestartCatalog fromQuarkusPlatformDescriptor(QuarkusPlatformDescriptor platformDescriptor) + public static QuarkusJBangCodestartCatalog fromResourceLoader(ResourceLoader resourceLoader) throws IOException { - final CodestartPathLoader pathLoader = platformPathLoader(platformDescriptor); + final CodestartPathLoader pathLoader = platformPathLoader(resourceLoader); final Collection<Codestart> codestarts = CodestartCatalogLoader.loadCodestarts(pathLoader, QUARKUS_JBANG_CODESTARTS_DIR); return new QuarkusJBangCodestartCatalog(codestarts); diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartCatalog.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartCatalog.java index f3a42620ab91ae..23987c70fc7b4b 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartCatalog.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartCatalog.java @@ -3,7 +3,6 @@ import static io.quarkus.devtools.codestarts.QuarkusPlatformCodestartResourceLoader.platformPathLoader; import static io.quarkus.devtools.codestarts.core.CodestartCatalogs.findLanguageName; -import io.quarkus.dependencies.Extension; import io.quarkus.devtools.codestarts.Codestart; import io.quarkus.devtools.codestarts.CodestartCatalogLoader; import io.quarkus.devtools.codestarts.CodestartException; @@ -11,9 +10,13 @@ import io.quarkus.devtools.codestarts.CodestartStructureException; import io.quarkus.devtools.codestarts.CodestartType; import io.quarkus.devtools.codestarts.DataKey; +import io.quarkus.devtools.codestarts.QuarkusPlatformCodestartResourceLoader; import io.quarkus.devtools.codestarts.core.GenericCodestartCatalog; +import io.quarkus.devtools.project.QuarkusProjectHelper; import io.quarkus.devtools.project.extensions.Extensions; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.platform.descriptor.loader.json.ResourceLoader; +import io.quarkus.registry.catalog.Extension; +import io.quarkus.registry.catalog.ExtensionCatalog; import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; @@ -62,18 +65,11 @@ private QuarkusCodestartCatalog(Collection<Codestart> codestarts, this.extensionsMapping = extensionsMapping; } - public static QuarkusCodestartCatalog fromQuarkusPlatformDescriptor(QuarkusPlatformDescriptor platformDescriptor) - throws IOException { - final CodestartPathLoader pathLoader = platformPathLoader(platformDescriptor); - final Collection<Codestart> codestarts = CodestartCatalogLoader.loadCodestarts(pathLoader, QUARKUS_CODESTARTS_DIR); - final Map<String, Extension> extensionsMapping = buildExtensionsMapping(platformDescriptor.getExtensions()); - return new QuarkusCodestartCatalog(codestarts, extensionsMapping); - } - public static QuarkusCodestartCatalog fromQuarkusPlatformDescriptorAndDirectories( - QuarkusPlatformDescriptor platformDescriptor, Collection<Path> directories) + ExtensionCatalog catalog, Collection<Path> directories) throws IOException { - final CodestartPathLoader pathLoader = platformPathLoader(platformDescriptor); + final CodestartPathLoader pathLoader = QuarkusPlatformCodestartResourceLoader + .platformPathLoader(QuarkusProjectHelper.getResourceLoader(catalog)); final Map<String, Codestart> codestarts = CodestartCatalogLoader.loadCodestarts(pathLoader, QUARKUS_CODESTARTS_DIR) .stream() .collect(Collectors.toMap(Codestart::getName, Function.identity())); @@ -83,10 +79,18 @@ public static QuarkusCodestartCatalog fromQuarkusPlatformDescriptorAndDirectorie // On duplicates, directories override platform codestarts codestarts.putAll(dirCodestarts); } - final Map<String, Extension> extensionsMapping = buildExtensionsMapping(platformDescriptor.getExtensions()); + final Map<String, Extension> extensionsMapping = buildExtensionsMapping(catalog.getExtensions()); return new QuarkusCodestartCatalog(codestarts.values(), extensionsMapping); } + public static QuarkusCodestartCatalog fromExtensionsCatalog(ExtensionCatalog catalog, ResourceLoader resourceLoader) + throws IOException { + final CodestartPathLoader pathLoader = platformPathLoader(resourceLoader); + final Collection<Codestart> codestarts = CodestartCatalogLoader.loadCodestarts(pathLoader, QUARKUS_CODESTARTS_DIR); + final Map<String, Extension> extensionCodestartMapping = buildExtensionsMapping(catalog.getExtensions()); + return new QuarkusCodestartCatalog(codestarts, extensionCodestartMapping); + } + @Override protected Collection<Codestart> select(QuarkusCodestartProjectInput projectInput) { // Add codestarts from extension and for tooling @@ -207,8 +211,15 @@ public static boolean isExample(Codestart codestart) { return codestart.getType() == CodestartType.CODE && codestart.getSpec().getTags().contains(Tag.EXAMPLE.key()); }; - private static Map<String, Extension> buildExtensionsMapping(Collection<Extension> extensions) { - return extensions.stream() - .collect(Collectors.toMap(Extensions::toGA, Function.identity())); + private static Map<String, Extension> buildExtensionsMapping( + Collection<Extension> extensions) { + final Map<String, Extension> map = new HashMap<>(extensions.size()); + extensions.forEach(e -> { + if (e.getCodestart() != null) { + map.put(e.getArtifact().getGroupId() + ":" + e.getArtifact().getArtifactId(), e); + } + }); + return map; } + } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/AddExtensions.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/AddExtensions.java index bef30a8ae8f652..c157105dc0c6b3 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/AddExtensions.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/AddExtensions.java @@ -11,7 +11,6 @@ import io.quarkus.devtools.project.extensions.ExtensionManager; import io.quarkus.platform.tools.ToolsConstants; import io.quarkus.platform.tools.ToolsUtils; -import io.quarkus.registry.ExtensionRegistry; import java.util.HashMap; import java.util.Set; @@ -24,7 +23,6 @@ public class AddExtensions { public static final String EXTENSIONS = ToolsUtils.dotJoin(ToolsConstants.QUARKUS, NAME, "extensions"); public static final String OUTCOME_UPDATED = ToolsUtils.dotJoin(ToolsConstants.QUARKUS, NAME, "outcome", "updated"); public static final String EXTENSION_MANAGER = ToolsUtils.dotJoin(ToolsConstants.QUARKUS, NAME, "extension-manager"); - public static final String EXTENSION_REGISTRY = ToolsUtils.dotJoin(ToolsConstants.QUARKUS, NAME, "extension-registry"); private final QuarkusCommandInvocation invocation; private final AddExtensionsCommandHandler handler = new AddExtensionsCommandHandler(); @@ -42,11 +40,6 @@ public AddExtensions extensionManager(ExtensionManager extensionManager) { return this; } - public AddExtensions extensionRegistry(ExtensionRegistry extensionRegistry) { - invocation.setValue(EXTENSION_REGISTRY, requireNonNull(extensionRegistry, "extensionRegistry is required")); - return this; - } - public AddExtensions extensions(Set<String> extensions) { invocation.setValue(EXTENSIONS, extensions); return this; diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/CreateJBangProject.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/CreateJBangProject.java index 8843f4f55cece2..c40162c5157274 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/CreateJBangProject.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/CreateJBangProject.java @@ -7,10 +7,7 @@ import io.quarkus.devtools.commands.data.QuarkusCommandInvocation; import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; import io.quarkus.devtools.commands.handlers.CreateJBangProjectCommandHandler; -import io.quarkus.devtools.project.BuildTool; import io.quarkus.devtools.project.QuarkusProject; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import java.nio.file.Path; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -19,16 +16,13 @@ public class CreateJBangProject { public static final String NAME = "create-jbang"; - private final Path projectDirPath; - private final QuarkusPlatformDescriptor platformDescr; - private BuildTool buildTool = BuildTool.MAVEN; + private final QuarkusProject quarkusProject; private Set<String> extensions = new HashSet<>(); private Map<String, Object> values = new HashMap<>(); - public CreateJBangProject(Path projectDirPath, QuarkusPlatformDescriptor platformDescr) { - this.projectDirPath = requireNonNull(projectDirPath, "projectDirPath is required"); - this.platformDescr = requireNonNull(platformDescr, "platformDescr is required"); + public CreateJBangProject(QuarkusProject quarkusProject) { + this.quarkusProject = requireNonNull(quarkusProject, "quarkusProject is required"); } public CreateJBangProject extensions(Set<String> extensions) { @@ -48,7 +42,6 @@ public CreateJBangProject setValue(String name, Object value) { public QuarkusCommandOutcome execute() throws QuarkusCommandException { setValue(EXTENSIONS, extensions); - final QuarkusProject quarkusProject = QuarkusProject.of(projectDirPath, platformDescr, buildTool); final QuarkusCommandInvocation invocation = new QuarkusCommandInvocation(quarkusProject, values); return new CreateJBangProjectCommandHandler().execute(invocation); } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/CreateProject.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/CreateProject.java index 51e83ea8095ff7..0c78f241e84e5c 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/CreateProject.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/CreateProject.java @@ -7,14 +7,11 @@ import io.quarkus.devtools.commands.data.QuarkusCommandInvocation; import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; import io.quarkus.devtools.commands.handlers.CreateProjectCommandHandler; -import io.quarkus.devtools.commands.handlers.LegacyCreateProjectCommandHandler; import io.quarkus.devtools.project.BuildTool; import io.quarkus.devtools.project.QuarkusProject; import io.quarkus.devtools.project.codegen.SourceType; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; import io.quarkus.platform.tools.ToolsConstants; import io.quarkus.platform.tools.ToolsUtils; -import java.nio.file.Path; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -42,18 +39,14 @@ public class CreateProject { private static final Pattern JAVA_VERSION_PATTERN = Pattern.compile("(?:1\\.)?(\\d+)(?:\\..*)?"); - private boolean legacyCodegen = false; - private final Path projectDirPath; - private final QuarkusPlatformDescriptor platformDescr; + private QuarkusProject quarkusProject; private String javaTarget; private Set<String> extensions = new HashSet<>(); - private BuildTool buildTool = BuildTool.MAVEN; private Map<String, Object> values = new HashMap<>(); - public CreateProject(final Path projectDirPath, QuarkusPlatformDescriptor platformDescr) { - this.projectDirPath = requireNonNull(projectDirPath, "projectDirPath is required"); - this.platformDescr = requireNonNull(platformDescr, "platformDescr is required"); + public CreateProject(QuarkusProject project) { + this.quarkusProject = requireNonNull(project, "project is required"); } public CreateProject groupId(String groupId) { @@ -71,16 +64,27 @@ public CreateProject version(String version) { return this; } + @Deprecated public CreateProject quarkusMavenPluginVersion(String version) { setValue(QUARKUS_MAVEN_PLUGIN_VERSION, version); return this; } + @Deprecated public CreateProject quarkusGradlePluginVersion(String version) { setValue(QUARKUS_GRADLE_PLUGIN_VERSION, version); return this; } + public CreateProject quarkusPluginVersion(String version) { + if (quarkusProject.getBuildTool().equals(BuildTool.MAVEN)) { + setValue(QUARKUS_MAVEN_PLUGIN_VERSION, version); + } else { + setValue(QUARKUS_GRADLE_PLUGIN_VERSION, version); + } + return this; + } + public CreateProject sourceType(SourceType sourceType) { setValue(SOURCE_TYPE, sourceType); return this; @@ -140,43 +144,6 @@ public CreateProject overrideExamples(Set<String> overrideExamples) { return this; } - /** - * @deprecated As of release 1.10, codestarts are default. Legacy codegen is scheduled to be removed: - * https://github.com/quarkusio/quarkus/issues/12897 - */ - @Deprecated - public CreateProject codestartsEnabled(boolean value) { - return this.legacyCodegen(!value); - } - - /** - * @deprecated As of release 1.10, codestarts are default. Legacy codegen is scheduled to be removed: - * https://github.com/quarkusio/quarkus/issues/12897 - */ - @Deprecated - public CreateProject codestartsEnabled() { - return this.legacyCodegen(false); - } - - /** - * @deprecated As of release 1.10, codestarts are default. Legacy codegen is scheduled to be removed: - * https://github.com/quarkusio/quarkus/issues/12897 - */ - @Deprecated - public CreateProject legacyCodegen() { - return this.legacyCodegen(true); - } - - /** - * @deprecated As of release 1.10, codestarts are default. Legacy codegen is scheduled to be removed: - * https://github.com/quarkusio/quarkus/issues/12897 - */ - @Deprecated - public CreateProject legacyCodegen(boolean value) { - this.legacyCodegen = value; - return this; - } - public CreateProject noExamples(boolean value) { setValue(NO_EXAMPLES, value); return this; @@ -211,11 +178,6 @@ public CreateProject setValue(String name, Object value) { return this; } - public CreateProject buildTool(BuildTool buildTool) { - this.buildTool = requireNonNull(buildTool, "buildTool is required"); - return this; - } - public boolean doCreateProject(final Map<String, Object> context) throws QuarkusCommandException { if (context != null && !context.isEmpty()) { for (Map.Entry<String, Object> entry : context.entrySet()) { @@ -244,11 +206,7 @@ public QuarkusCommandOutcome execute() throws QuarkusCommandException { } } setValue(EXTENSIONS, extensions); - final QuarkusProject quarkusProject = QuarkusProject.of(projectDirPath, platformDescr, buildTool); final QuarkusCommandInvocation invocation = new QuarkusCommandInvocation(quarkusProject, values); - if (legacyCodegen) { - return new LegacyCreateProjectCommandHandler().execute(invocation); - } return new CreateProjectCommandHandler().execute(invocation); } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/ListExtensions.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/ListExtensions.java index 8e777a62165f81..f19a132d98925c 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/ListExtensions.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/ListExtensions.java @@ -11,7 +11,6 @@ import io.quarkus.devtools.project.extensions.ExtensionManager; import io.quarkus.platform.tools.ToolsConstants; import io.quarkus.platform.tools.ToolsUtils; -import io.quarkus.registry.ExtensionRegistry; import java.util.HashMap; /** @@ -26,7 +25,6 @@ public class ListExtensions { public static final String FORMAT = ToolsUtils.dotJoin(PARAM_PREFIX, "format"); public static final String SEARCH = ToolsUtils.dotJoin(PARAM_PREFIX, "search"); public static final String EXTENSION_MANAGER = ToolsUtils.dotJoin(PARAM_PREFIX, "extension-manager"); - public static final String EXTENSION_REGISTRY = ToolsUtils.dotJoin(PARAM_PREFIX, "extension-registry"); private final QuarkusCommandInvocation invocation; private final ListExtensionsCommandHandler handler = new ListExtensionsCommandHandler(); @@ -64,11 +62,6 @@ public ListExtensions extensionManager(ExtensionManager extensionManager) { return this; } - public ListExtensions extensionRegistry(ExtensionRegistry extensionRegistry) { - invocation.setValue(EXTENSION_REGISTRY, requireNonNull(extensionRegistry, "extensionRegistry is required")); - return this; - } - public ListExtensions search(String search) { invocation.setValue(SEARCH, search); return this; diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/ListPlatforms.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/ListPlatforms.java new file mode 100644 index 00000000000000..191c93b6a1e23b --- /dev/null +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/ListPlatforms.java @@ -0,0 +1,27 @@ +package io.quarkus.devtools.commands; + +import io.quarkus.devtools.commands.data.QuarkusCommandException; +import io.quarkus.devtools.commands.data.QuarkusCommandInvocation; +import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; +import io.quarkus.devtools.commands.handlers.ListPlatformsCommandHandler; +import io.quarkus.devtools.messagewriter.MessageWriter; +import io.quarkus.devtools.project.QuarkusProject; +import java.util.HashMap; + +public class ListPlatforms { + + private final QuarkusCommandInvocation invocation; + private final ListPlatformsCommandHandler handler = new ListPlatformsCommandHandler(); + + public ListPlatforms(QuarkusProject quarkusProject) { + this.invocation = new QuarkusCommandInvocation(quarkusProject); + } + + public ListPlatforms(QuarkusProject quarkusProject, MessageWriter messageWriter) { + this.invocation = new QuarkusCommandInvocation(quarkusProject, new HashMap<>(), messageWriter); + } + + public QuarkusCommandOutcome execute() throws QuarkusCommandException { + return handler.execute(invocation); + } +} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/data/QuarkusCommandInvocation.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/data/QuarkusCommandInvocation.java index 4470fa21e42f05..a46feadfaf8a1d 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/data/QuarkusCommandInvocation.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/data/QuarkusCommandInvocation.java @@ -4,7 +4,7 @@ import io.quarkus.devtools.messagewriter.MessageWriter; import io.quarkus.devtools.project.QuarkusProject; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.registry.catalog.ExtensionCatalog; import java.util.HashMap; import java.util.Map; @@ -40,8 +40,7 @@ public MessageWriter log() { return log; } - public QuarkusPlatformDescriptor getPlatformDescriptor() { - return quarkusProject.getPlatformDescriptor(); + public ExtensionCatalog getExtensionsCatalog() { + return quarkusProject.getExtensionsCatalog(); } - } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/data/SelectionResult.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/data/SelectionResult.java index c97d6afcc0a313..4ab793f86aa216 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/data/SelectionResult.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/data/SelectionResult.java @@ -1,21 +1,21 @@ package io.quarkus.devtools.commands.data; -import io.quarkus.dependencies.Extension; +import io.quarkus.registry.catalog.Extension; +import java.util.Collection; import java.util.Collections; import java.util.Iterator; -import java.util.Set; public class SelectionResult implements Iterable<Extension> { - private final Set<Extension> extensions; + private final Collection<Extension> extensions; private final boolean matches; - public SelectionResult(Set<Extension> extensions, boolean matches) { + public SelectionResult(Collection<Extension> extensions, boolean matches) { this.extensions = extensions; this.matches = matches; } - public Set<Extension> getExtensions() { + public Collection<Extension> getExtensions() { return extensions; } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/AddExtensionsCommandHandler.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/AddExtensionsCommandHandler.java index cfd2475e67dba6..3f7a694471dde9 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/AddExtensionsCommandHandler.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/AddExtensionsCommandHandler.java @@ -3,6 +3,8 @@ import static io.quarkus.devtools.commands.AddExtensions.EXTENSION_MANAGER; import static io.quarkus.devtools.messagewriter.MessageIcons.NOK_ICON; +import io.quarkus.bootstrap.model.AppArtifactCoords; +import io.quarkus.bootstrap.model.AppArtifactKey; import io.quarkus.devtools.commands.AddExtensions; import io.quarkus.devtools.commands.data.QuarkusCommandException; import io.quarkus.devtools.commands.data.QuarkusCommandInvocation; @@ -11,12 +13,18 @@ import io.quarkus.devtools.project.extensions.ExtensionInstallPlan; import io.quarkus.devtools.project.extensions.ExtensionManager; import io.quarkus.devtools.project.extensions.ExtensionManager.InstallResult; -import io.quarkus.registry.DefaultExtensionRegistry; -import io.quarkus.registry.ExtensionRegistry; -import io.quarkus.registry.MultipleExtensionsFoundException; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.catalog.Extension; +import io.quarkus.registry.catalog.ExtensionCatalog; +import io.quarkus.registry.catalog.ExtensionOrigin; +import io.quarkus.registry.catalog.ExtensionPredicate; import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Set; +import org.apache.commons.lang3.StringUtils; /** * This class is thread-safe. It extracts extensions to be added to the project from an instance of @@ -31,16 +39,13 @@ public QuarkusCommandOutcome execute(QuarkusCommandInvocation invocation) throws return QuarkusCommandOutcome.success().setValue(AddExtensions.OUTCOME_UPDATED, false); } - ExtensionRegistry extensionRegistry = invocation.getValue(AddExtensions.EXTENSION_REGISTRY); - if (extensionRegistry == null) { - extensionRegistry = DefaultExtensionRegistry.fromPlatform(invocation.getPlatformDescriptor()); - } - String quarkusVersion = invocation.getPlatformDescriptor().getQuarkusVersion(); + String quarkusVersion = invocation.getExtensionsCatalog().getQuarkusCoreVersion(); final ExtensionManager extensionManager = invocation.getValue(EXTENSION_MANAGER, invocation.getQuarkusProject().getExtensionManager()); try { - ExtensionInstallPlan extensionInstallPlan = extensionRegistry.planInstallation(quarkusVersion, extensionsQuery); + ExtensionInstallPlan extensionInstallPlan = planInstallation(quarkusVersion, extensionsQuery, + invocation.getExtensionsCatalog()); if (extensionInstallPlan.isNotEmpty()) { final InstallResult result = extensionManager.install(extensionInstallPlan); result.getInstalled() @@ -65,4 +70,83 @@ public QuarkusCommandOutcome execute(QuarkusCommandInvocation invocation) throws return new QuarkusCommandOutcome(false).setValue(AddExtensions.OUTCOME_UPDATED, false); } + public ExtensionInstallPlan planInstallation(String quarkusCore, Collection<String> keywords, + ExtensionCatalog catalog) { + ExtensionInstallPlan.Builder builder = ExtensionInstallPlan.builder(); + boolean multipleKeywords = keywords.size() > 1; + for (String keyword : keywords) { + int countColons = StringUtils.countMatches(keyword, ":"); + // Check if it's just groupId:artifactId + if (countColons == 1) { + AppArtifactKey artifactKey = AppArtifactKey.fromString(keyword); + builder.addManagedExtension(new AppArtifactCoords(artifactKey, null)); + continue; + } else if (countColons > 1) { + // it's a gav + builder.addIndependentExtension(AppArtifactCoords.fromString(keyword)); + continue; + } + List<Extension> listed = listInternalExtensions(quarkusCore, keyword, catalog.getExtensions()); + if (listed.size() != 1 && multipleKeywords) { + // No extension found for this keyword. Return empty immediately + return ExtensionInstallPlan.EMPTY; + } + // If it's a pattern allow multiple results + // See https://github.com/quarkusio/quarkus/issues/11086#issuecomment-666360783 + else if (listed.size() > 1 && !ExtensionPredicate.isPattern(keyword)) { + throw new MultipleExtensionsFoundException(keyword, listed); + } + for (Extension e : listed) { + String groupId = e.getArtifact().getGroupId(); + String artifactId = e.getArtifact().getArtifactId(); + String version = e.getArtifact().getVersion(); + AppArtifactCoords extensionCoords = new AppArtifactCoords(groupId, artifactId, version); + + boolean managed = false; + // TODO this is not properly picking the platform BOMs + for (ExtensionOrigin origin : e.getOrigins()) { + if (origin.isPlatform()) { + builder.addManagedExtension(extensionCoords); + final ArtifactCoords bomCoords = origin.getBom(); + builder.addPlatform(new AppArtifactCoords(bomCoords.getGroupId(), bomCoords.getArtifactId(), + null, "pom", bomCoords.getVersion())); + managed = true; + break; + } + } + if (!managed) { + builder.addIndependentExtension(extensionCoords); + } + } + // TODO + //if (!listed.isEmpty()) { + // builder.addPlatform(new AppArtifactCoords(catalog.getBomGroupId(), catalog.getBomArtifactId(), null, "pom", + // catalog.getBomVersion())); + //} + } + return builder.build(); + } + + private List<Extension> listInternalExtensions(String quarkusCore, String keyword, Collection<Extension> extensions) { + List<Extension> result = new ArrayList<>(); + ExtensionPredicate predicate = null; + if (keyword != null && !keyword.isEmpty()) { + predicate = new ExtensionPredicate(keyword); + } + for (Extension extension : extensions) { + // If no filter is defined, just return the tuple + if (predicate == null) { + result.add(extension); + } else { + // If there is an exact match, return only this + if (predicate.isExactMatch(extension)) { + return Collections.singletonList(extension); + } else if (predicate.test(extension)) { + result.add(extension); + } + } + } + return result; + } + } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/CreateJBangProjectCommandHandler.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/CreateJBangProjectCommandHandler.java index 826cc668100cdb..daf07947d68eef 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/CreateJBangProjectCommandHandler.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/CreateJBangProjectCommandHandler.java @@ -1,19 +1,19 @@ package io.quarkus.devtools.commands.handlers; -import static io.quarkus.devtools.codestarts.jbang.QuarkusJBangCodestartCatalog.JBangDataKey.QUARKUS_BOM_ARTIFACT_ID; -import static io.quarkus.devtools.codestarts.jbang.QuarkusJBangCodestartCatalog.JBangDataKey.QUARKUS_BOM_GROUP_ID; -import static io.quarkus.devtools.codestarts.jbang.QuarkusJBangCodestartCatalog.JBangDataKey.QUARKUS_BOM_VERSION; import static io.quarkus.devtools.commands.handlers.QuarkusCommandHandlers.computeCoordsFromQuery; import io.quarkus.bootstrap.model.AppArtifactCoords; import io.quarkus.devtools.codestarts.jbang.QuarkusJBangCodestartCatalog; import io.quarkus.devtools.codestarts.jbang.QuarkusJBangCodestartProjectInput; +import io.quarkus.devtools.codestarts.jbang.QuarkusJBangCodestartProjectInputBuilder; import io.quarkus.devtools.commands.data.QuarkusCommandException; import io.quarkus.devtools.commands.data.QuarkusCommandInvocation; import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; import io.quarkus.devtools.messagewriter.MessageIcons; +import io.quarkus.devtools.project.QuarkusProject; import io.quarkus.devtools.project.codegen.ProjectGenerator; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.catalog.ExtensionCatalog; import java.io.IOException; import java.nio.file.Path; import java.util.Collections; @@ -30,13 +30,24 @@ public QuarkusCommandOutcome execute(QuarkusCommandInvocation invocation) throws throw new QuarkusCommandException("Failed to create project because of invalid extensions"); } - final QuarkusJBangCodestartProjectInput input = QuarkusJBangCodestartProjectInput.builder() + final ExtensionCatalog catalog = invocation.getExtensionsCatalog(); + + final QuarkusJBangCodestartProjectInputBuilder builder = QuarkusJBangCodestartProjectInput.builder() .addExtensions(extensionsToAdd) .setNoJBangWrapper(invocation.getBooleanValue("noJBangWrapper")) - .putData(QUARKUS_BOM_GROUP_ID, invocation.getPlatformDescriptor().getBomGroupId()) - .putData(QUARKUS_BOM_ARTIFACT_ID, invocation.getPlatformDescriptor().getBomArtifactId()) - .putData(QUARKUS_BOM_VERSION, invocation.getPlatformDescriptor().getBomVersion()) - .build(); + .putData("quarkus.version", invocation.getExtensionsCatalog().getQuarkusCoreVersion()); + + if (catalog.getBom() != null) { + // TODO properly import the BOMs + final ArtifactCoords firstBom = catalog.getBom(); + builder.putData(QuarkusJBangCodestartCatalog.JBangDataKey.QUARKUS_BOM_GROUP_ID.key(), + firstBom.getGroupId()) + .putData(QuarkusJBangCodestartCatalog.JBangDataKey.QUARKUS_BOM_ARTIFACT_ID.key(), + firstBom.getArtifactId()) + .putData(QuarkusJBangCodestartCatalog.JBangDataKey.QUARKUS_BOM_VERSION.key(), + firstBom.getVersion()); + } + final QuarkusJBangCodestartProjectInput input = builder.build(); final Path projectDir = invocation.getQuarkusProject().getProjectDirPath(); try { @@ -46,7 +57,7 @@ public QuarkusCommandOutcome execute(QuarkusCommandInvocation invocation) throws + extensionsToAdd.stream().map(e -> "- " + e.getGroupId() + ":" + e.getArtifactId() + "\n") .collect(Collectors.joining())); } - getCatalog(invocation.getPlatformDescriptor()).createProject(input).generate(projectDir); + getCatalog(invocation.getQuarkusProject()).createProject(input).generate(projectDir); invocation.log() .info("\n-----------\n" + MessageIcons.NOOP_ICON + " jbang project has been successfully generated in:\n--> " @@ -57,7 +68,7 @@ public QuarkusCommandOutcome execute(QuarkusCommandInvocation invocation) throws return QuarkusCommandOutcome.success(); } - private QuarkusJBangCodestartCatalog getCatalog(QuarkusPlatformDescriptor platformDescriptor) throws IOException { - return QuarkusJBangCodestartCatalog.fromQuarkusPlatformDescriptor(platformDescriptor); + private QuarkusJBangCodestartCatalog getCatalog(QuarkusProject project) throws IOException { + return QuarkusJBangCodestartCatalog.fromResourceLoader(project.getCodestartsResourceLoader()); } } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/CreateProjectCommandHandler.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/CreateProjectCommandHandler.java index 8e65c76429181f..ae235cbbe29efa 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/CreateProjectCommandHandler.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/CreateProjectCommandHandler.java @@ -25,8 +25,9 @@ import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; import io.quarkus.devtools.messagewriter.MessageIcons; import io.quarkus.devtools.project.codegen.ProjectGenerator; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.maven.ArtifactCoords; import io.quarkus.platform.tools.ToolsUtils; +import io.quarkus.registry.catalog.ExtensionCatalog; import java.io.IOException; import java.util.Collections; import java.util.HashMap; @@ -45,11 +46,15 @@ public class CreateProjectCommandHandler implements QuarkusCommandHandler { @Override public QuarkusCommandOutcome execute(QuarkusCommandInvocation invocation) throws QuarkusCommandException { - final QuarkusPlatformDescriptor platformDescr = invocation.getPlatformDescriptor(); - invocation.setValue(BOM_GROUP_ID, platformDescr.getBomGroupId()); - invocation.setValue(BOM_ARTIFACT_ID, platformDescr.getBomArtifactId()); - invocation.setValue(QUARKUS_VERSION, platformDescr.getQuarkusVersion()); - invocation.setValue(BOM_VERSION, platformDescr.getBomVersion()); + final ExtensionCatalog platformDescr = invocation.getExtensionsCatalog(); + final ArtifactCoords bom = platformDescr.getBom(); + if (bom == null) { + throw new QuarkusCommandException("The platform BOM is missing"); + } + invocation.setValue(BOM_GROUP_ID, bom.getGroupId()); + invocation.setValue(BOM_ARTIFACT_ID, bom.getArtifactId()); + invocation.setValue(BOM_VERSION, bom.getVersion()); + invocation.setValue(QUARKUS_VERSION, platformDescr.getQuarkusCoreVersion()); final Set<String> extensionsQuery = invocation.getValue(ProjectGenerator.EXTENSIONS, Collections.emptySet()); final Properties quarkusProps = ToolsUtils.readQuarkusProperties(platformDescr); @@ -106,7 +111,8 @@ public QuarkusCommandOutcome execute(QuarkusCommandInvocation invocation) throws } final QuarkusCodestartCatalog catalog = QuarkusCodestartCatalog - .fromQuarkusPlatformDescriptor(invocation.getPlatformDescriptor()); + .fromExtensionsCatalog(invocation.getQuarkusProject().getExtensionsCatalog(), + invocation.getQuarkusProject().getCodestartsResourceLoader()); final CodestartProjectDefinition projectDefinition = catalog.createProject(input); projectDefinition.generate(invocation.getQuarkusProject().getProjectDirPath()); invocation.log() diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/LegacyCreateProjectCommandHandler.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/LegacyCreateProjectCommandHandler.java deleted file mode 100644 index e4fd4e1e8389e8..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/LegacyCreateProjectCommandHandler.java +++ /dev/null @@ -1,203 +0,0 @@ -package io.quarkus.devtools.commands.handlers; - -import static io.quarkus.devtools.commands.handlers.QuarkusCommandHandlers.computeCoordsFromQuery; -import static io.quarkus.devtools.project.codegen.ProjectGenerator.*; - -import io.quarkus.bootstrap.model.AppArtifactCoords; -import io.quarkus.devtools.codestarts.utils.NestedMaps; -import io.quarkus.devtools.commands.data.QuarkusCommandException; -import io.quarkus.devtools.commands.data.QuarkusCommandInvocation; -import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; -import io.quarkus.devtools.messagewriter.MessageIcons; -import io.quarkus.devtools.project.BuildTool; -import io.quarkus.devtools.project.buildfile.GroovyGradleBuildFilesCreator; -import io.quarkus.devtools.project.buildfile.KotlinGradleBuildFilesCreator; -import io.quarkus.devtools.project.codegen.ProjectGenerator; -import io.quarkus.devtools.project.codegen.ProjectGeneratorRegistry; -import io.quarkus.devtools.project.codegen.SourceType; -import io.quarkus.devtools.project.codegen.rest.BasicRestProjectGenerator; -import io.quarkus.devtools.project.extensions.ExtensionManager; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.tools.ToolsUtils; -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Properties; -import java.util.Set; - -/** - * Instances of this class are thread-safe. They create a new project extracting all the necessary properties from an instance - * of {@link QuarkusCommandInvocation}. - */ -public class LegacyCreateProjectCommandHandler implements QuarkusCommandHandler { - - @Override - public QuarkusCommandOutcome execute(QuarkusCommandInvocation invocation) throws QuarkusCommandException { - final QuarkusPlatformDescriptor platformDescr = invocation.getPlatformDescriptor(); - invocation.setValue(BOM_GROUP_ID, platformDescr.getBomGroupId()); - invocation.setValue(BOM_ARTIFACT_ID, platformDescr.getBomArtifactId()); - invocation.setValue(QUARKUS_VERSION, platformDescr.getQuarkusVersion()); - invocation.setValue(BOM_VERSION, platformDescr.getBomVersion()); - final Set<String> extensionsQuery = invocation.getValue(ProjectGenerator.EXTENSIONS, Collections.emptySet()); - - final Properties quarkusProps = ToolsUtils.readQuarkusProperties(platformDescr); - quarkusProps.forEach((k, v) -> { - String name = k.toString().replace("-", "_"); - if (!invocation.hasValue(name)) { - invocation.setValue(k.toString().replace("-", "_"), v.toString()); - } - }); - - addPlatformDataToLegacyCodegen(invocation); - - try { - String className = invocation.getStringValue(CLASS_NAME); - if (className != null) { - className = invocation.getValue(SOURCE_TYPE, SourceType.JAVA).stripExtensionFrom(className); - int idx = className.lastIndexOf('.'); - if (idx >= 0) { - String pkgName = invocation.getStringValue(PACKAGE_NAME); - if (pkgName == null) { - invocation.setValue(PACKAGE_NAME, className.substring(0, idx)); - } - className = className.substring(idx + 1); - } - invocation.setValue(CLASS_NAME, className); - } - - // Default to cleaned groupId if packageName not set - final String pkgName = invocation.getStringValue(PACKAGE_NAME); - final String groupId = invocation.getStringValue(PROJECT_GROUP_ID); - if (pkgName == null && groupId != null) { - invocation.setValue(PACKAGE_NAME, groupId.replace("-", ".").replace("_", ".")); - } - - final List<AppArtifactCoords> extensionsToAdd = computeCoordsFromQuery(invocation, extensionsQuery); - - // extensionsToAdd is null when an error occurred while matching extensions - if (extensionsToAdd != null) { - ProjectGeneratorRegistry.get(BasicRestProjectGenerator.NAME).generate(invocation); - - //TODO ia3andy extensions should be added directly during the project generation - if (invocation.getQuarkusProject().getBuildTool().equals(BuildTool.GRADLE)) { - final GroovyGradleBuildFilesCreator generator = new GroovyGradleBuildFilesCreator( - invocation.getQuarkusProject()); - generator.create( - invocation.getStringValue(PROJECT_GROUP_ID), - invocation.getStringValue(PROJECT_ARTIFACT_ID), - invocation.getStringValue(PROJECT_VERSION), - quarkusProps, - extensionsToAdd); - } else if (invocation.getQuarkusProject().getBuildTool().equals(BuildTool.GRADLE_KOTLIN_DSL)) { - final KotlinGradleBuildFilesCreator generator = new KotlinGradleBuildFilesCreator( - invocation.getQuarkusProject()); - generator.create( - invocation.getStringValue(PROJECT_GROUP_ID), - invocation.getStringValue(PROJECT_ARTIFACT_ID), - invocation.getStringValue(PROJECT_VERSION), - quarkusProps, - extensionsToAdd); - } else { - final ExtensionManager.InstallResult result = invocation.getQuarkusProject().getExtensionManager() - .install(extensionsToAdd); - result.getInstalled() - .forEach(a -> invocation.log() - .info(MessageIcons.OK_ICON + " Extension " + a.getGroupId() + ":" + a.getArtifactId() - + " has been installed")); - } - } - } catch (IOException e) { - throw new QuarkusCommandException("Failed to create project", e); - } - return QuarkusCommandOutcome.success(); - } - - // # CLOSE YOUR EYES PLEASE - static void addPlatformDataToLegacyCodegen(QuarkusCommandInvocation invocation) { - final BuildTool buildTool = invocation.getQuarkusProject().getBuildTool(); - if (BuildTool.MAVEN == buildTool) { - final Optional<List> mavenRepositories = NestedMaps.getValue(invocation.getPlatformDescriptor().getMetadata(), - "maven.repositories"); - if (mavenRepositories.isPresent() - && !mavenRepositories.get().isEmpty()) { - // We only take the first one here to make things simpler: - final Map<String, Object> repo = (Map<String, Object>) mavenRepositories.get().get(0); - if (repo != null && repo.get("id") instanceof String && repo.get("url") instanceof String) { - final StringBuilder repositories = new StringBuilder() - .append("\n") - .append(" <repositories>\n") - .append(" <repository>\n") - .append(" <id>").append(repo.get("id")).append("</id>\n") - .append(" <url>").append(repo.get("url")).append("</url>\n") - .append(" <releases>\n") - .append(" <enabled>").append(repo.getOrDefault("releases-enabled", true)) - .append("</enabled>\n") - .append(" </releases>\n") - .append(" <snapshots>\n") - .append(" <enabled>").append(repo.getOrDefault("snapshots-enabled", true)) - .append("</enabled>\n") - .append(" </snapshots>\n") - .append(" </repository>\n") - .append(" </repositories>\n"); - invocation.setValue(MAVEN_REPOSITORIES, repositories.toString()); - } - } - final Optional<List> mavenPluginRepositories = NestedMaps - .getValue(invocation.getPlatformDescriptor().getMetadata(), "maven.plugin-repositories"); - if (mavenPluginRepositories.isPresent() - && !mavenPluginRepositories.get().isEmpty()) { - // We only take the first one here to make things simpler: - final Map<String, Object> repo = (Map<String, Object>) mavenPluginRepositories.get().get(0); - if (repo != null && repo.get("id") instanceof String && repo.get("url") instanceof String) { - final StringBuilder pluginRepositories = new StringBuilder() - .append("\n") - .append(" <pluginRepositories>\n") - .append(" <pluginRepository>\n") - .append(" <id>").append(repo.get("id")).append("</id>\n") - .append(" <url>").append(repo.get("url")).append("</url>\n") - .append(" <releases>\n") - .append(" <enabled>").append(repo.getOrDefault("releases-enabled", true)) - .append("</enabled>\n") - .append(" </releases>\n") - .append(" <snapshots>\n") - .append(" <enabled>").append(repo.getOrDefault("snapshots-enabled", true)) - .append("</enabled>\n") - .append(" </snapshots>\n") - .append(" </pluginRepository>\n") - .append(" </pluginRepositories>\n"); - invocation.setValue(MAVEN_PLUGIN_REPOSITORIES, pluginRepositories.toString()); - } - } - } else if (BuildTool.GRADLE == buildTool || BuildTool.GRADLE_KOTLIN_DSL == buildTool) { - final Optional<List> gradleRepositories = NestedMaps - .getValue(invocation.getPlatformDescriptor().getMetadata(), "gradle.repositories"); - if (gradleRepositories.isPresent() - && !gradleRepositories.get().isEmpty()) { - // We only take the first one here to make things simpler: - final Map<String, Object> repo = (Map<String, Object>) gradleRepositories.get().get(0); - if (repo != null && repo.get("url") instanceof String) { - final String repositories = buildTool == BuildTool.GRADLE - ? "\n maven { url \"" + repo.get("url") + "\" }" - : "\n maven { url = uri(\"" + repo.get("url") + "\") }"; - invocation.setValue(MAVEN_REPOSITORIES, repositories); - } - } - final Optional<List> gradlePluginRepositories = NestedMaps - .getValue(invocation.getPlatformDescriptor().getMetadata(), "gradle.plugin-repositories"); - if (gradlePluginRepositories.isPresent() - && !gradlePluginRepositories.get().isEmpty()) { - // We only take the first one here to make things simpler: - final Map<String, Object> repo = (Map<String, Object>) gradlePluginRepositories.get().get(0); - if (repo != null && repo.get("url") instanceof String) { - final String pluginRepositories = buildTool == BuildTool.GRADLE - ? "\n maven { url \"" + repo.get("url") + "\" }" - : "\n maven { url = uri(\"" + repo.get("url") + "\") }"; - invocation.setValue(MAVEN_PLUGIN_REPOSITORIES, pluginRepositories); - } - } - } - } - // # YOU CAN OPEN NOW :) -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/ListExtensionsCommandHandler.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/ListExtensionsCommandHandler.java index 9544073e89b166..b8cc1238c903bb 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/ListExtensionsCommandHandler.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/ListExtensionsCommandHandler.java @@ -5,7 +5,6 @@ import io.quarkus.bootstrap.model.AppArtifactCoords; import io.quarkus.bootstrap.model.AppArtifactKey; -import io.quarkus.dependencies.Extension; import io.quarkus.devtools.commands.ListExtensions; import io.quarkus.devtools.commands.data.QuarkusCommandException; import io.quarkus.devtools.commands.data.QuarkusCommandInvocation; @@ -13,12 +12,12 @@ import io.quarkus.devtools.messagewriter.MessageWriter; import io.quarkus.devtools.project.BuildTool; import io.quarkus.devtools.project.extensions.ExtensionManager; -import io.quarkus.registry.DefaultExtensionRegistry; -import io.quarkus.registry.ExtensionRegistry; +import io.quarkus.registry.catalog.Extension; +import io.quarkus.registry.catalog.ExtensionOrigin; import java.io.IOException; import java.util.Collection; +import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.function.BiConsumer; import java.util.function.Function; @@ -28,9 +27,10 @@ */ public class ListExtensionsCommandHandler implements QuarkusCommandHandler { - private static final String FULL_FORMAT = "%-8s %-50s %-50s %-25s%n%s"; + private static final String FULL_FORMAT = "%-8s %-50s %-50s %-25s%s"; private static final String CONCISE_FORMAT = "%-50s %-50s"; private static final String NAME_FORMAT = "%-50s"; + private static final String ORIGINS_FORMAT = "%-50s %-60s %s"; @Override public QuarkusCommandOutcome execute(QuarkusCommandInvocation invocation) throws QuarkusCommandException { @@ -43,10 +43,40 @@ public QuarkusCommandOutcome execute(QuarkusCommandInvocation invocation) throws final String search = invocation.getValue(ListExtensions.SEARCH, "*"); final ExtensionManager extensionManager = invocation.getValue(ListExtensions.EXTENSION_MANAGER, invocation.getQuarkusProject().getExtensionManager()); - ExtensionRegistry extensionRegistry = invocation.getValue(ListExtensions.EXTENSION_REGISTRY); - if (extensionRegistry == null) { - extensionRegistry = DefaultExtensionRegistry.fromPlatform(invocation.getPlatformDescriptor()); + + final Collection<Extension> extensions = search == null ? invocation.getExtensionsCatalog().getExtensions() + : QuarkusCommandHandlers.select(search, invocation.getExtensionsCatalog().getExtensions(), true) + .getExtensions(); + + if (extensions.isEmpty()) { + log.info("No extension found with pattern '%s'", search); + return QuarkusCommandOutcome.success(); + } + + if (!cli) { + String extensionStatus = all ? "available" : "installable"; + if (installedOnly) + extensionStatus = "installed"; + log.info("%nCurrent Quarkus extensions %s: ", extensionStatus); + } + + BiConsumer<MessageWriter, Object[]> currentFormatter; + switch (format.toLowerCase()) { + case "name": + currentFormatter = this::nameFormatter; + break; + case "full": + currentFormatter = this::fullFormatter; + log.info(String.format(FULL_FORMAT, "Status", "Extension", "ArtifactId", "Updated Version", "Guide")); + break; + case "origins": + currentFormatter = this::originsFormatter; + break; + case "concise": + default: + currentFormatter = this::conciseFormatter; } + Map<AppArtifactKey, AppArtifactCoords> installedByKey; try { installedByKey = extensionManager.getInstalled().stream() @@ -54,78 +84,74 @@ public QuarkusCommandOutcome execute(QuarkusCommandInvocation invocation) throws } catch (IOException e) { throw new QuarkusCommandException("Failed to determine the list of installed extensions", e); } - String quarkusVersion = invocation.getPlatformDescriptor().getQuarkusVersion(); - Collection<Extension> platformExtensions = extensionRegistry.list(quarkusVersion, search); - if (platformExtensions.isEmpty()) { - log.info("No extension found with pattern '%s'", search); - } else { - if (!cli) { - String extensionStatus = all ? "available" : "installable"; - if (installedOnly) - extensionStatus = "installed"; - log.info("%nCurrent Quarkus extensions %s: ", extensionStatus); - } - - BiConsumer<MessageWriter, String[]> currentFormatter; - switch (format.toLowerCase()) { - case "name": - currentFormatter = this::nameFormatter; - break; - case "full": - currentFormatter = this::fullFormatter; - currentFormatter.accept(log, - new String[] { "Status", "Extension", "ArtifactId", "Updated Version", "Guide" }); - break; - case "concise": - default: - currentFormatter = this::conciseFormatter; - } - - platformExtensions.forEach(platformExtension -> display(log, platformExtension, - installedByKey.get(toKey(platformExtension)), all, installedOnly, currentFormatter)); - final BuildTool buildTool = invocation.getQuarkusProject().getBuildTool(); - boolean isGradle = BuildTool.GRADLE.equals(buildTool) || BuildTool.GRADLE_KOTLIN_DSL.equals(buildTool); - - if (!cli) { - if ("concise".equalsIgnoreCase(format)) { - if (isGradle) { - log.info("\nTo get more information, append --format=full to your command line."); - } else { - log.info( - "\nTo get more information, append -Dquarkus.extension.format=full to your command line."); - } - } - + extensions.stream() + .filter(e -> !e.isUnlisted()) + .forEach(e -> display(log, e, installedByKey.get(toKey(e)), all, installedOnly, currentFormatter)); + final BuildTool buildTool = invocation.getQuarkusProject().getBuildTool(); + boolean isGradle = BuildTool.GRADLE.equals(buildTool) || BuildTool.GRADLE_KOTLIN_DSL.equals(buildTool); + + if (!cli) { + if ("concise".equalsIgnoreCase(format)) { if (isGradle) { - log.info("\nAdd an extension to your project by adding the dependency to your " + - "build.gradle or use `./gradlew addExtension --extensions=\"artifactId\"`"); + log.info("\nTo get more information, append --format=full to your command line."); } else { - log.info("\nAdd an extension to your project by adding the dependency to your " + - "pom.xml or use `./mvnw quarkus:add-extension -Dextensions=\"artifactId\"`"); + log.info( + "\nTo get more information, append -Dquarkus.extension.format=full to your command line."); } } + if (isGradle) { + log.info("\nAdd an extension to your project by adding the dependency to your " + + "build.gradle or use `./gradlew addExtension --extensions=\"artifactId\"`"); + } else { + log.info("\nAdd an extension to your project by adding the dependency to your " + + "pom.xml or use `./mvnw quarkus:add-extension -Dextensions=\"artifactId\"`"); + } } return QuarkusCommandOutcome.success(); } - private void conciseFormatter(MessageWriter writer, String[] cols) { - writer.info(String.format(CONCISE_FORMAT, cols[1], cols[2])); + private void conciseFormatter(MessageWriter writer, Object[] cols) { + Extension e = (Extension) cols[1]; + writer.info(String.format(CONCISE_FORMAT, e.getName(), e.getArtifact().getArtifactId())); } - private void fullFormatter(MessageWriter writer, String[] cols) { - writer.info(String.format(FULL_FORMAT, cols[0], cols[1], cols[2], cols[3], cols[4])); + private void fullFormatter(MessageWriter writer, Object[] cols) { + Extension e = (Extension) cols[1]; + writer.info(String.format(FULL_FORMAT, cols[0], e.getName(), e.getArtifact().getArtifactId(), cols[2], + e.getGuide() == null ? "" : e.getGuide())); } - private void nameFormatter(MessageWriter writer, String[] cols) { - writer.info(String.format(NAME_FORMAT, cols[2])); + private void nameFormatter(MessageWriter writer, Object[] cols) { + Extension e = (Extension) cols[1]; + writer.info(String.format(NAME_FORMAT, e.getArtifact().getArtifactId())); } - private void display(MessageWriter messageWriter, final Extension platformExtension, final AppArtifactCoords installed, + private void originsFormatter(MessageWriter writer, Object[] cols) { + Extension e = (Extension) cols[1]; + String origin = null; + int i = 0; + final List<ExtensionOrigin> origins = e.getOrigins(); + while (i < origins.size() && origin == null) { + final ExtensionOrigin o = origins.get(i++); + if (o.isPlatform()) { + origin = o.getBom().toString(); + } + } + writer.info(String.format(ORIGINS_FORMAT, e.getName(), e.getArtifact().getVersion(), origin == null ? "" : origin)); + while (i < origins.size()) { + final ExtensionOrigin o = origins.get(i++); + if (o.isPlatform()) { + writer.info(String.format(ORIGINS_FORMAT, "", "", o.getBom().toString())); + } + } + } + + private void display(MessageWriter messageWriter, final Extension e, final AppArtifactCoords installed, boolean all, boolean installedOnly, - BiConsumer<MessageWriter, String[]> formatter) { + BiConsumer<MessageWriter, Object[]> formatter) { if (installedOnly && installed == null) { return; } @@ -140,24 +166,17 @@ private void display(MessageWriter messageWriter, final Extension platformExtens final String installedVersion = installed.getVersion(); if (installedVersion == null) { label = "default"; - version = platformExtension.getVersion(); - } else if (installedVersion.equalsIgnoreCase(platformExtension.getVersion())) { + version = e.getArtifact().getVersion(); + } else if (installedVersion.equalsIgnoreCase(e.getArtifact().getVersion())) { label = "custom"; version = installedVersion; } else { label = "custom*"; - version = String.format("%s* <> %s", installedVersion, platformExtension.getVersion()); + version = String.format("%s* <> %s", installedVersion, e.getArtifact().getVersion()); } } - String[] result = new String[] { label, platformExtension.getName(), platformExtension.getArtifactId(), version, - platformExtension.getGuide() }; - - for (int i = 0; i < result.length; i++) { - result[i] = Objects.toString(result[i], ""); - } - - formatter.accept(messageWriter, result); + formatter.accept(messageWriter, new Object[] { label, e, version }); } } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/ListPlatformsCommandHandler.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/ListPlatformsCommandHandler.java new file mode 100644 index 00000000000000..c2b23ad05b3b7e --- /dev/null +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/ListPlatformsCommandHandler.java @@ -0,0 +1,27 @@ +package io.quarkus.devtools.commands.handlers; + +import io.quarkus.devtools.commands.data.QuarkusCommandException; +import io.quarkus.devtools.commands.data.QuarkusCommandInvocation; +import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; +import io.quarkus.devtools.messagewriter.MessageWriter; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.catalog.ExtensionCatalog; +import io.quarkus.registry.catalog.ExtensionOrigin; + +public class ListPlatformsCommandHandler implements QuarkusCommandHandler { + + @Override + public QuarkusCommandOutcome execute(QuarkusCommandInvocation invocation) throws QuarkusCommandException { + final ExtensionCatalog catalog = invocation.getQuarkusProject().getExtensionsCatalog(); + logPlatform(catalog, invocation.log()); + catalog.getDerivedFrom().forEach(o -> logPlatform(o, invocation.log())); + return QuarkusCommandOutcome.success(); + } + + private static void logPlatform(ExtensionOrigin o, MessageWriter log) { + final ArtifactCoords bom = o.isPlatform() ? o.getBom() : null; + if (bom != null) { + log.info(bom.toString()); + } + } +} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/MultipleExtensionsFoundException.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/MultipleExtensionsFoundException.java similarity index 69% rename from independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/MultipleExtensionsFoundException.java rename to independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/MultipleExtensionsFoundException.java index d036b8393b1dee..571d1ebfba405e 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/MultipleExtensionsFoundException.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/MultipleExtensionsFoundException.java @@ -1,14 +1,11 @@ -package io.quarkus.registry; +package io.quarkus.devtools.commands.handlers; -import io.quarkus.dependencies.Extension; +import io.quarkus.registry.catalog.Extension; import java.util.Collection; import java.util.Objects; /** - * Thrown when multiple extensions are found for a given extension when - * {@link ExtensionRegistry#planInstallation(String, Collection)} is called - * - * @see {@link ExtensionRegistry#planInstallation(String, Collection)} + * Thrown when multiple extensions are found for a given installation plan */ public class MultipleExtensionsFoundException extends RuntimeException { diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/QuarkusCommandHandlers.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/QuarkusCommandHandlers.java index 3a80dde24a6ba0..70a75f0e0e4bd0 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/QuarkusCommandHandlers.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/QuarkusCommandHandlers.java @@ -5,15 +5,16 @@ import io.quarkus.bootstrap.model.AppArtifactCoords; import io.quarkus.bootstrap.model.AppArtifactKey; -import io.quarkus.dependencies.Extension; import io.quarkus.devtools.commands.data.QuarkusCommandInvocation; import io.quarkus.devtools.commands.data.SelectionResult; import io.quarkus.devtools.project.extensions.Extensions; +import io.quarkus.maven.ArtifactKey; +import io.quarkus.registry.catalog.Extension; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashSet; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; @@ -35,7 +36,7 @@ static List<AppArtifactCoords> computeCoordsFromQuery(final QuarkusCommandInvoca } else if (countColons > 1) { builder.add(AppArtifactCoords.fromString(query)); } else { - Collection<Extension> extensions = invocation.getPlatformDescriptor().getExtensions(); + Collection<Extension> extensions = invocation.getExtensionsCatalog().getExtensions(); SelectionResult result = select(query, extensions, false); if (result.matches()) { final Set<AppArtifactCoords> withStrippedVersion = result.getExtensions().stream().map(Extensions::toCoords) @@ -46,7 +47,7 @@ static List<AppArtifactCoords> computeCoordsFromQuery(final QuarkusCommandInvoca StringBuilder sb = new StringBuilder(); // We have 3 cases, we can still have a single candidate, but the match is on label // or we have several candidates, or none - Set<Extension> candidates = result.getExtensions(); + Collection<Extension> candidates = result.getExtensions(); if (candidates.isEmpty()) { // No matches at all. invocation.log().error("Cannot find a dependency matching '" + query + "', maybe a typo?"); @@ -71,77 +72,73 @@ static List<AppArtifactCoords> computeCoordsFromQuery(final QuarkusCommandInvoca * Selection algorithm. * * @param query the query - * @param allPlatformExtensions the list of all platform extensions + * @param allExtensions the list of all platform extensions * @param labelLookup whether or not the query must be tested against the labels of the extensions. Should * be {@code false} by default. * @return the list of matching candidates and whether or not a match has been found. */ - static SelectionResult select(final String query, final Collection<Extension> allPlatformExtensions, + static SelectionResult select(final String query, final Collection<Extension> allExtensions, final boolean labelLookup) { String q = query.trim().toLowerCase(); - // Try exact matches - Set<Extension> matchesNameOrArtifactId = allPlatformExtensions.stream() - .filter(extension -> extension.getName().equalsIgnoreCase(q) || matchesArtifactId(extension.getArtifactId(), q)) - .collect(Collectors.toSet()); - if (matchesNameOrArtifactId.size() == 1) { - return new SelectionResult(matchesNameOrArtifactId, true); - } + final Map<ArtifactKey, Extension> matches = new LinkedHashMap<>(); - final List<Extension> listedPlatformExtensions = allPlatformExtensions.stream() - .filter(e -> !e.isUnlisted()).collect(Collectors.toList()); + if (!isExpression(q)) { + // Try exact matches + allExtensions.stream() + .filter(extension -> extension.getName().equalsIgnoreCase(q) + || matchesArtifactId(extension.getArtifact().getArtifactId(), q)) + .forEach(e -> matches.putIfAbsent(e.getArtifact().getKey(), e)); + if (matches.size() == 1) { + return new SelectionResult(matches.values(), true); + } - // Try short names - Set<Extension> matchesShortName = listedPlatformExtensions.stream().filter(extension -> matchesShortName(extension, q)) - .collect(Collectors.toSet()); + final List<Extension> listedExtensions = getListedExtensions(allExtensions); - if (matchesShortName.size() == 1 && matchesNameOrArtifactId.isEmpty()) { - return new SelectionResult(matchesShortName, true); - } + // Try short names + listedExtensions.stream().filter(extension -> matchesShortName(extension, q)) + .forEach(e -> matches.putIfAbsent(e.getArtifact().getKey(), e)); + if (matches.size() == 1) { + return new SelectionResult(matches.values(), true); + } - // Partial matches on name, artifactId and short names - Set<Extension> partialMatches = listedPlatformExtensions.stream() - .filter(extension -> extension.getName().toLowerCase().contains(q) - || extension.getArtifactId().toLowerCase().contains(q) - || extension.getShortName().toLowerCase().contains(q)) - .collect(Collectors.toSet()); - // Even if we have a single partial match, if the name, artifactId and short names are ambiguous, so not - // consider it as a match. - if (partialMatches.size() == 1 && matchesNameOrArtifactId.isEmpty() && matchesShortName.isEmpty()) { - return new SelectionResult(partialMatches, true); - } + // Partial matches on name, artifactId and short names + listedExtensions.stream() + .filter(extension -> extension.getName().toLowerCase().contains(q) + || extension.getArtifact().getArtifactId().toLowerCase().contains(q) + || extension.getShortName().toLowerCase().contains(q)) + .forEach(e -> matches.putIfAbsent(e.getArtifact().getKey(), e)); + // Even if we have a single partial match, if the name, artifactId and short names are ambiguous, so not + // consider it as a match. + if (matches.size() == 1) { + return new SelectionResult(matches.values(), true); + } - // find by labels - List<Extension> matchesLabels; - if (labelLookup) { - matchesLabels = listedPlatformExtensions.stream() - .filter(extension -> extension.labelsForMatching().contains(q)).collect(Collectors.toList()); - } else { - matchesLabels = Collections.emptyList(); + // find by labels + if (labelLookup) { + listedExtensions.stream() + .filter(extension -> extension.labelsForMatching().contains(q)) + .forEach(e -> matches.put(e.getArtifact().getKey(), e)); + } + return new SelectionResult(matches.values(), false); } - + final List<Extension> listedExtensions = getListedExtensions(allExtensions); // find by pattern - Set<Extension> matchesPatterns; Pattern pattern = toRegex(q); if (pattern != null) { - matchesPatterns = listedPlatformExtensions.stream() + listedExtensions.stream() .filter(extension -> pattern.matcher(extension.getName().toLowerCase()).matches() - || pattern.matcher(extension.getArtifactId().toLowerCase()).matches() + || pattern.matcher(extension.getArtifact().getArtifactId().toLowerCase()).matches() || pattern.matcher(extension.getShortName().toLowerCase()).matches() || matchLabels(pattern, extension.getKeywords())) - .collect(Collectors.toSet()); - return new SelectionResult(matchesPatterns, true); - } else { - matchesPatterns = Collections.emptySet(); + .forEach(e -> matches.putIfAbsent(e.getArtifact().getKey(), e)); } + return new SelectionResult(matches.values(), !matches.isEmpty()); + } - Set<Extension> candidates = new LinkedHashSet<>(); - candidates.addAll(matchesNameOrArtifactId); - candidates.addAll(matchesShortName); - candidates.addAll(partialMatches); - candidates.addAll(matchesLabels); - candidates.addAll(matchesPatterns); - return new SelectionResult(candidates, false); + private static List<Extension> getListedExtensions(final Collection<Extension> allExtensions) { + return allExtensions.stream() + .filter(e -> !e.isUnlisted()).collect(Collectors.toList()); } private static boolean matchLabels(Pattern pattern, List<String> labels) { @@ -166,11 +163,8 @@ private static Pattern toRegex(final String str) { } private static String wildcardToRegex(String wildcard) { - if (wildcard == null || wildcard.isEmpty()) { - return null; - } // don't try with file match char in pattern - if (!(wildcard.contains("*") || wildcard.contains("?"))) { + if (!isExpression(wildcard)) { return null; } StringBuffer s = new StringBuffer(wildcard.length()); @@ -210,6 +204,10 @@ private static String wildcardToRegex(String wildcard) { return (s.toString()); } + private static boolean isExpression(String s) { + return s == null || s.isEmpty() ? false : s.contains("*") || s.contains("?"); + } + private static boolean matchesShortName(Extension extension, String q) { return q.equalsIgnoreCase(extension.getShortName()); } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/RemoveExtensionsCommandHandler.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/RemoveExtensionsCommandHandler.java index 56f863acb113ba..798a187841b5d5 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/RemoveExtensionsCommandHandler.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/handlers/RemoveExtensionsCommandHandler.java @@ -38,20 +38,16 @@ public QuarkusCommandOutcome execute(QuarkusCommandInvocation invocation) throws final ExtensionManager extensionManager = invocation.getValue(EXTENSION_MANAGER, invocation.getQuarkusProject().getExtensionManager()); try { - if (extensionsToRemove != null) { - final Set<AppArtifactKey> keys = extensionsToRemove.stream().map(AppArtifactCoords::getKey) - .collect(Collectors.toSet()); - final UninstallResult result = extensionManager.uninstall(keys); - result.getUninstalled() - .forEach(a -> invocation.log() - .info(MessageIcons.OK_ICON + " Extension " + a.getGroupId() + ":" + a.getArtifactId() - + " has been uninstalled")); - return new QuarkusCommandOutcome(true).setValue(RemoveExtensions.OUTCOME_UPDATED, result.isSourceUpdated()); - } + final Set<AppArtifactKey> keys = extensionsToRemove.stream().map(AppArtifactCoords::getKey) + .collect(Collectors.toSet()); + final UninstallResult result = extensionManager.uninstall(keys); + result.getUninstalled() + .forEach(a -> invocation.log() + .info(MessageIcons.OK_ICON + " Extension " + a.getGroupId() + ":" + a.getArtifactId() + + " has been uninstalled")); + return new QuarkusCommandOutcome(true).setValue(RemoveExtensions.OUTCOME_UPDATED, result.isSourceUpdated()); } catch (IOException e) { throw new QuarkusCommandException("Failed to remove extensions", e); } - - return new QuarkusCommandOutcome(true).setValue(RemoveExtensions.OUTCOME_UPDATED, false); } } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/BuildTool.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/BuildTool.java index fb59fa39d4421e..9678932a9ae176 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/BuildTool.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/BuildTool.java @@ -4,7 +4,7 @@ import io.quarkus.devtools.project.buildfile.KotlinGradleBuildFile; import io.quarkus.devtools.project.buildfile.MavenBuildFile; import io.quarkus.devtools.project.extensions.ExtensionManager; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.registry.catalog.ExtensionCatalog; import java.nio.file.Path; /** @@ -59,7 +59,7 @@ public String getBuildDirectory() { } public ExtensionManager createExtensionManager(final Path projectDirPath, - final QuarkusPlatformDescriptor platformDescriptor) { + ExtensionCatalog catalog) { switch (this) { case GRADLE: return new GroovyGradleBuildFile(); @@ -67,7 +67,7 @@ public ExtensionManager createExtensionManager(final Path projectDirPath, return new KotlinGradleBuildFile(); case MAVEN: default: - return new MavenBuildFile(projectDirPath, platformDescriptor); + return new MavenBuildFile(projectDirPath, catalog); } } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/QuarkusProject.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/QuarkusProject.java index 976040c3a961e3..bc98410fcb6ccb 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/QuarkusProject.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/QuarkusProject.java @@ -2,47 +2,38 @@ import static java.util.Objects.requireNonNull; -import io.quarkus.devtools.project.buildfile.MavenBuildFile; +import io.quarkus.devtools.messagewriter.MessageWriter; import io.quarkus.devtools.project.extensions.ExtensionManager; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.platform.descriptor.loader.json.ResourceLoader; +import io.quarkus.registry.catalog.ExtensionCatalog; import java.nio.file.Path; public final class QuarkusProject { private final Path projectDirPath; - private final QuarkusPlatformDescriptor platformDescriptor; + private ExtensionCatalog catalog; + private ResourceLoader resourceLoader; private final ExtensionManager extensionManager; - private QuarkusProject(final Path projectDirPath, final QuarkusPlatformDescriptor platformDescriptor, - final ExtensionManager extensionManager) { + private QuarkusProject(Path projectDirPath, ExtensionCatalog catalog, ResourceLoader codestartPathLoader, + MessageWriter log, + ExtensionManager extensionManager) { this.projectDirPath = requireNonNull(projectDirPath, "projectDirPath is required"); - this.platformDescriptor = requireNonNull(platformDescriptor, "platformDescriptor is required"); + this.catalog = requireNonNull(catalog, "catalog is required"); + this.resourceLoader = requireNonNull(codestartPathLoader, "resourceLoader is required"); this.extensionManager = requireNonNull(extensionManager, "extensionManager is required"); } - public static QuarkusProject of(final Path projectDirPath, final QuarkusPlatformDescriptor platformDescriptor, + public static QuarkusProject of(final Path projectDirPath, final ExtensionCatalog catalog, + ResourceLoader resourceLoader, MessageWriter log, final ExtensionManager extensionManager) { - return new QuarkusProject(projectDirPath, platformDescriptor, extensionManager); - } - - public static QuarkusProject of(final Path projectDirPath, final QuarkusPlatformDescriptor platformDescriptor, - final BuildTool buildTool) { - return new QuarkusProject(projectDirPath, platformDescriptor, - buildTool.createExtensionManager(projectDirPath, platformDescriptor)); - } - - public static QuarkusProject maven(final Path projectDirPath, final QuarkusPlatformDescriptor platformDescriptor) { - return new QuarkusProject(projectDirPath, platformDescriptor, - new MavenBuildFile(projectDirPath, platformDescriptor)); + return new QuarkusProject(projectDirPath, catalog, resourceLoader, log, extensionManager); } - public static QuarkusProject resolveExistingProject(final Path projectDirPath, - final QuarkusPlatformDescriptor descriptor) { - final BuildTool buildTool = resolveExistingProjectBuildTool(projectDirPath); - if (buildTool == null) { - throw new IllegalStateException("This is neither a Maven or Gradle project"); - } - return of(projectDirPath, descriptor, buildTool); + public static QuarkusProject of(Path projectDirPath, ExtensionCatalog catalog, ResourceLoader codestartsResourceLoader, + MessageWriter log, BuildTool buildTool) { + return new QuarkusProject(projectDirPath, catalog, codestartsResourceLoader, log, + buildTool.createExtensionManager(projectDirPath, catalog)); } public Path getProjectDirPath() { @@ -57,8 +48,12 @@ public ExtensionManager getExtensionManager() { return extensionManager; } - public QuarkusPlatformDescriptor getPlatformDescriptor() { - return platformDescriptor; + public ExtensionCatalog getExtensionsCatalog() { + return catalog; + } + + public ResourceLoader getCodestartsResourceLoader() { + return resourceLoader; } public static BuildTool resolveExistingProjectBuildTool(Path projectDirPath) { diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/QuarkusProjectHelper.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/QuarkusProjectHelper.java new file mode 100644 index 00000000000000..3f17041afc77c0 --- /dev/null +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/QuarkusProjectHelper.java @@ -0,0 +1,171 @@ +package io.quarkus.devtools.project; + +import io.quarkus.bootstrap.model.AppArtifactCoords; +import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; +import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; +import io.quarkus.devtools.messagewriter.MessageWriter; +import io.quarkus.devtools.project.extensions.ExtensionManager; +import io.quarkus.platform.descriptor.loader.json.ClassPathResourceLoader; +import io.quarkus.platform.tools.ToolsConstants; +import io.quarkus.platform.tools.ToolsUtils; +import io.quarkus.registry.ExtensionCatalogResolver; +import io.quarkus.registry.RegistryResolutionException; +import io.quarkus.registry.catalog.ExtensionCatalog; +import io.quarkus.registry.config.RegistriesConfig; +import io.quarkus.registry.config.RegistriesConfigLocator; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.DefaultArtifact; + +public class QuarkusProjectHelper { + + private static final String CODESTARTS_ARTIFACTS = "codestarts-artifacts"; + + private static RegistriesConfig toolsConfig; + private static MessageWriter log; + private static MavenArtifactResolver artifactResolver; + private static ExtensionCatalogResolver catalogResolver; + + public static QuarkusProject getProject(Path projectDir) { + BuildTool buildTool = QuarkusProject.resolveExistingProjectBuildTool(projectDir); + if (buildTool == null) { + buildTool = BuildTool.MAVEN; + } + return getProject(projectDir, buildTool); + } + + public static QuarkusProject getProject(Path projectDir, String quarkusVersion) { + // TODO remove this method once the default registry becomes available + BuildTool buildTool = QuarkusProject.resolveExistingProjectBuildTool(projectDir); + if (buildTool == null) { + buildTool = BuildTool.MAVEN; + } + return getProject(projectDir, buildTool, quarkusVersion); + } + + public static QuarkusProject getProject(Path projectDir, BuildTool buildTool, String quarkusVersion) { + // TODO remove this method once the default registry becomes available + final ExtensionCatalogResolver catalogResolver = getCatalogResolver(); + if (catalogResolver.hasRegistries()) { + return getProject(projectDir, buildTool); + } + return QuarkusProjectHelper.getProject(projectDir, + ToolsUtils.resolvePlatformDescriptorDirectly(null, null, quarkusVersion, artifactResolver(), messageWriter()), + buildTool); + } + + public static QuarkusProject getProject(Path projectDir, BuildTool buildTool) { + final ExtensionCatalog catalog; + try { + catalog = resolveExtensionCatalog(); + } catch (Exception e) { + throw new RuntimeException("Failed to resolve the Quarkus extension catalog", e); + } + + return getProject(projectDir, catalog, buildTool, messageWriter()); + } + + public static QuarkusProject getProject(Path projectDir, ExtensionCatalog catalog, BuildTool buildTool) { + return getProject(projectDir, catalog, buildTool, messageWriter()); + } + + public static QuarkusProject getProject(Path projectDir, ExtensionCatalog catalog, BuildTool buildTool, + MessageWriter log) { + return QuarkusProject.of(projectDir, catalog, getResourceLoader(catalog, artifactResolver()), + log, buildTool); + } + + public static QuarkusProject getProject(Path projectDir, ExtensionManager extManager) throws RegistryResolutionException { + return getProject(projectDir, resolveExtensionCatalog(), extManager, messageWriter()); + } + + public static ExtensionCatalog resolveExtensionCatalog() throws RegistryResolutionException { + return getCatalogResolver().resolveExtensionCatalog(); + } + + public static QuarkusProject getProject(Path projectDir, ExtensionCatalog catalog, ExtensionManager extManager, + MessageWriter log) { + return QuarkusProject.of(projectDir, catalog, getResourceLoader(catalog, artifactResolver()), + log, extManager); + } + + public static ClassPathResourceLoader getResourceLoader(ExtensionCatalog catalog) { + return getResourceLoader(catalog, artifactResolver()); + } + + public static ClassPathResourceLoader getResourceLoader(ExtensionCatalog catalog, MavenArtifactResolver mvn) { + Object o = catalog.getMetadata().get(CODESTARTS_ARTIFACTS); + final List<Artifact> codestartsArtifacts; + if (o == null) { + // This is hardcoded temporarily + codestartsArtifacts = Arrays + .asList(new DefaultArtifact(ToolsConstants.IO_QUARKUS, "quarkus-platform-descriptor-json", "", "jar", + catalog.getQuarkusCoreVersion())); + } else { + @SuppressWarnings({ "unchecked" }) + final List<Object> list = o instanceof List ? (List<Object>) o : Arrays.asList(o); + codestartsArtifacts = new ArrayList<>(list.size()); + for (Object i : list) { + AppArtifactCoords coords = AppArtifactCoords.fromString(i.toString()); + codestartsArtifacts.add(new DefaultArtifact(coords.getGroupId(), coords.getArtifactId(), coords.getClassifier(), + coords.getType(), coords.getVersion())); + } + } + + final URL[] urls = new URL[codestartsArtifacts.size()]; + for (int i = 0; i < codestartsArtifacts.size(); ++i) { + try { + urls[i] = mvn.resolve(codestartsArtifacts.get(i)).getArtifact().getFile().toURI().toURL(); + } catch (Exception e) { + throw new RuntimeException("Failed to resolve codestart artifact " + codestartsArtifacts.get(i), e); + } + } + + return new ClassPathResourceLoader(new URLClassLoader(urls, null)); + } + + public static ExtensionCatalogResolver getCatalogResolver() { + return catalogResolver == null ? catalogResolver = getCatalogResolver(artifactResolver(), messageWriter()) + : catalogResolver; + } + + public static ExtensionCatalogResolver getCatalogResolver(MessageWriter log) { + return catalogResolver == null ? catalogResolver = getCatalogResolver(artifactResolver(), log) + : catalogResolver; + } + + public static ExtensionCatalogResolver getCatalogResolver(MavenArtifactResolver resolver, MessageWriter log) { + return ExtensionCatalogResolver.builder() + .artifactResolver(resolver) + .config(toolsConfig()) + .messageWriter(log) + .build(); + } + + private static RegistriesConfig toolsConfig() { + return toolsConfig == null ? toolsConfig = RegistriesConfigLocator.resolveConfig() : toolsConfig; + } + + private static MessageWriter messageWriter() { + return log == null ? log = toolsConfig().isDebug() ? MessageWriter.debug() : MessageWriter.info() : log; + } + + private static MavenArtifactResolver artifactResolver() { + if (artifactResolver == null) { + try { + artifactResolver = MavenArtifactResolver.builder() + .setArtifactTransferLogging(toolsConfig().isDebug()) + .setWorkspaceDiscovery(false) + .build(); + } catch (BootstrapMavenException e) { + throw new IllegalStateException("Failed to initialize the Maven artifact resolver", e); + } + } + return artifactResolver; + } +} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractGradleBuildFile.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractGradleBuildFile.java index d981fe23cb76e6..2a7f495f1a2269 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractGradleBuildFile.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractGradleBuildFile.java @@ -2,7 +2,7 @@ import io.quarkus.bootstrap.model.AppArtifactCoords; import io.quarkus.bootstrap.model.AppArtifactKey; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.registry.catalog.ExtensionCatalog; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -27,13 +27,13 @@ abstract class AbstractGradleBuildFile extends BuildFile { private final AtomicReference<Model> modelReference = new AtomicReference<>(); - public AbstractGradleBuildFile(final Path projectDirPath, final QuarkusPlatformDescriptor platformDescriptor) { - this(projectDirPath, platformDescriptor, null); + public AbstractGradleBuildFile(final Path projectDirPath, final ExtensionCatalog catalog) { + this(projectDirPath, catalog, null); } - public AbstractGradleBuildFile(final Path projectDirPath, final QuarkusPlatformDescriptor platformDescriptor, + public AbstractGradleBuildFile(final Path projectDirPath, final ExtensionCatalog catalog, Path rootProjectPath) { - super(projectDirPath, platformDescriptor); + super(projectDirPath, catalog); this.rootProjectPath = rootProjectPath; } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractGradleBuildFilesCreator.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractGradleBuildFilesCreator.java index 1e0da5432ab958..8bae8894e615ae 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractGradleBuildFilesCreator.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractGradleBuildFilesCreator.java @@ -3,8 +3,9 @@ import io.quarkus.bootstrap.model.AppArtifactCoords; import io.quarkus.devtools.project.QuarkusProject; import io.quarkus.devtools.project.buildfile.AbstractGradleBuildFile.Model; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.maven.ArtifactCoords; import io.quarkus.platform.tools.ToolsUtils; +import io.quarkus.registry.catalog.ExtensionCatalog; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -122,20 +123,21 @@ protected void writeToProjectFile(final String fileName, final byte[] content) t } private void createProperties() throws IOException { - final QuarkusPlatformDescriptor platform = quarkusProject.getPlatformDescriptor(); + final ExtensionCatalog platform = quarkusProject.getExtensionsCatalog(); Properties props = getModel().getPropertiesContent(); if (props.getProperty("quarkusPluginVersion") == null) { props.setProperty("quarkusPluginVersion", ToolsUtils.getGradlePluginVersion(ToolsUtils.readQuarkusProperties(platform))); } + final ArtifactCoords bom = platform.getBom(); if (props.getProperty("quarkusPlatformGroupId") == null) { - props.setProperty("quarkusPlatformGroupId", platform.getBomGroupId()); + props.setProperty("quarkusPlatformGroupId", bom.getGroupId()); } if (props.getProperty("quarkusPlatformArtifactId") == null) { - props.setProperty("quarkusPlatformArtifactId", platform.getBomArtifactId()); + props.setProperty("quarkusPlatformArtifactId", bom.getArtifactId()); } if (props.getProperty("quarkusPlatformVersion") == null) { - props.setProperty("quarkusPlatformVersion", platform.getBomVersion()); + props.setProperty("quarkusPlatformVersion", bom.getVersion()); } } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractGroovyGradleBuildFile.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractGroovyGradleBuildFile.java index 3cc1acb842165a..1296a842cf7b0e 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractGroovyGradleBuildFile.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractGroovyGradleBuildFile.java @@ -2,7 +2,7 @@ import io.quarkus.bootstrap.model.AppArtifactCoords; import io.quarkus.devtools.project.BuildTool; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.registry.catalog.ExtensionCatalog; import java.nio.file.Path; public abstract class AbstractGroovyGradleBuildFile extends AbstractGradleBuildFile { @@ -10,13 +10,13 @@ public abstract class AbstractGroovyGradleBuildFile extends AbstractGradleBuildF static final String BUILD_GRADLE_PATH = "build.gradle"; static final String SETTINGS_GRADLE_PATH = "settings.gradle"; - public AbstractGroovyGradleBuildFile(Path projectDirPath, QuarkusPlatformDescriptor platformDescriptor) { - super(projectDirPath, platformDescriptor); + public AbstractGroovyGradleBuildFile(Path projectDirPath, ExtensionCatalog catalog) { + super(projectDirPath, catalog); } - public AbstractGroovyGradleBuildFile(Path projectDirPath, QuarkusPlatformDescriptor platformDescriptor, + public AbstractGroovyGradleBuildFile(Path projectDirPath, ExtensionCatalog catalog, Path rootProjectPath) { - super(projectDirPath, platformDescriptor, rootProjectPath); + super(projectDirPath, catalog, rootProjectPath); } @Override diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractKotlinGradleBuildFile.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractKotlinGradleBuildFile.java deleted file mode 100644 index abe1582185163c..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/AbstractKotlinGradleBuildFile.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.quarkus.devtools.project.buildfile; - -import io.quarkus.bootstrap.model.AppArtifactCoords; -import io.quarkus.devtools.project.BuildTool; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import java.nio.file.Path; - -public abstract class AbstractKotlinGradleBuildFile extends AbstractGradleBuildFile { - - static final String BUILD_GRADLE_PATH = "build.gradle.kts"; - static final String SETTINGS_GRADLE_PATH = "settings.gradle.kts"; - - public AbstractKotlinGradleBuildFile(Path projectDirPath, QuarkusPlatformDescriptor platformDescriptor) { - super(projectDirPath, platformDescriptor); - } - - public AbstractKotlinGradleBuildFile(Path projectDirPath, QuarkusPlatformDescriptor platformDescriptor, - Path rootProjectPath) { - super(projectDirPath, platformDescriptor, rootProjectPath); - } - - @Override - String getSettingsGradlePath() { - return SETTINGS_GRADLE_PATH; - } - - @Override - String getBuildGradlePath() { - return BUILD_GRADLE_PATH; - } - - @Override - protected boolean addDependency(AppArtifactCoords coords, boolean managed) { - return addDependencyInModel(getModel(), coords, managed); - } - - @Override - public BuildTool getBuildTool() { - return BuildTool.GRADLE_KOTLIN_DSL; - } - - static boolean addDependencyInModel(Model model, AppArtifactCoords coords, boolean managed) { - return addDependencyInModel(model, - String.format(" implementation(%s)%n", createDependencyCoordinatesString(coords, managed, '"'))); - } - -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/BuildFile.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/BuildFile.java index 74e852db3078fc..811ca352715c8a 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/BuildFile.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/BuildFile.java @@ -1,15 +1,16 @@ package io.quarkus.devtools.project.buildfile; -import static io.quarkus.devtools.project.extensions.Extensions.findInList; import static java.util.Objects.requireNonNull; import static java.util.stream.Collectors.toList; import io.quarkus.bootstrap.model.AppArtifactCoords; import io.quarkus.bootstrap.model.AppArtifactKey; -import io.quarkus.dependencies.Extension; import io.quarkus.devtools.project.extensions.ExtensionInstallPlan; import io.quarkus.devtools.project.extensions.ExtensionManager; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.devtools.project.extensions.Extensions; +import io.quarkus.maven.ArtifactKey; +import io.quarkus.registry.catalog.Extension; +import io.quarkus.registry.catalog.ExtensionCatalog; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; @@ -17,17 +18,19 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; public abstract class BuildFile implements ExtensionManager { private final Path projectDirPath; - private final QuarkusPlatformDescriptor platformDescriptor; + private final ExtensionCatalog catalog; - public BuildFile(final Path projectDirPath, final QuarkusPlatformDescriptor platformDescriptor) { + public BuildFile(final Path projectDirPath, ExtensionCatalog catalog) { this.projectDirPath = requireNonNull(projectDirPath, "projectPath is required"); - this.platformDescriptor = requireNonNull(platformDescriptor, "platformDescriptor is required"); + this.catalog = requireNonNull(catalog, "catalog is required"); } @Override @@ -127,16 +130,24 @@ protected void writeToProjectFile(final String fileName, final byte[] content) t } private boolean isQuarkusExtension(final AppArtifactKey key) { - // This will not always be true as the platform descriptor does not contain the list of all available extensions - return isDefinedInRegistry(platformDescriptor.getExtensions(), key); + if (catalog != null) { + return findInList(catalog.getExtensions(), key).isPresent(); + } + return isDefinedInRegistry(catalog.getExtensions(), key); } private Set<AppArtifactKey> getDependenciesKeys() throws IOException { return getDependencies().stream().map(AppArtifactCoords::getKey).collect(Collectors.toSet()); } - public static boolean isDefinedInRegistry(List<Extension> registry, final AppArtifactKey key) { - return findInList(registry, key).isPresent(); + public static boolean isDefinedInRegistry(Collection<Extension> registry, final AppArtifactKey key) { + return Extensions.findInList(registry, key).isPresent(); + } + + private static Optional<io.quarkus.registry.catalog.Extension> findInList( + Collection<io.quarkus.registry.catalog.Extension> list, final AppArtifactKey key) { + ArtifactKey k = new ArtifactKey(key.getGroupId(), key.getArtifactId(), key.getClassifier(), key.getType()); + return list.stream().filter(e -> Objects.equals(e.getArtifact().getKey(), k)).findFirst(); } } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/GroovyGradleBuildFilesCreator.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/GroovyGradleBuildFilesCreator.java index e825a78b299c37..7e5c6affbeb3fd 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/GroovyGradleBuildFilesCreator.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/GroovyGradleBuildFilesCreator.java @@ -2,6 +2,7 @@ import io.quarkus.bootstrap.model.AppArtifactCoords; import io.quarkus.devtools.project.QuarkusProject; +import io.quarkus.maven.ArtifactCoords; import java.io.IOException; public final class GroovyGradleBuildFilesCreator extends AbstractGradleBuildFilesCreator { @@ -30,8 +31,8 @@ void createBuildContent(String groupId, String version) throws IOException { res.append(System.lineSeparator()).append(" id 'io.quarkus'").append(System.lineSeparator()); res.append("}"); } - if (!containsBOM(getQuarkusProject().getPlatformDescriptor().getBomGroupId(), - getQuarkusProject().getPlatformDescriptor().getBomArtifactId())) { + final ArtifactCoords bom = getQuarkusProject().getExtensionsCatalog().getBom(); + if (!containsBOM(bom.getGroupId(), bom.getArtifactId())) { res.append(System.lineSeparator()); res.append("dependencies {").append(System.lineSeparator()); res.append( diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/KotlinGradleBuildFilesCreator.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/KotlinGradleBuildFilesCreator.java index 679a9d27927451..7715483cd94744 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/KotlinGradleBuildFilesCreator.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/KotlinGradleBuildFilesCreator.java @@ -2,22 +2,27 @@ import io.quarkus.bootstrap.model.AppArtifactCoords; import io.quarkus.devtools.project.QuarkusProject; +import io.quarkus.devtools.project.buildfile.AbstractGradleBuildFile.Model; +import io.quarkus.maven.ArtifactCoords; import java.io.IOException; public class KotlinGradleBuildFilesCreator extends AbstractGradleBuildFilesCreator { + static final String BUILD_GRADLE_PATH = "build.gradle.kts"; + static final String SETTINGS_GRADLE_PATH = "settings.gradle.kts"; + public KotlinGradleBuildFilesCreator(QuarkusProject quarkusProject) { super(quarkusProject); } @Override String getSettingsGradlePath() { - return AbstractKotlinGradleBuildFile.SETTINGS_GRADLE_PATH; + return SETTINGS_GRADLE_PATH; } @Override String getBuildGradlePath() { - return AbstractKotlinGradleBuildFile.BUILD_GRADLE_PATH; + return BUILD_GRADLE_PATH; } @Override @@ -30,8 +35,8 @@ void createBuildContent(String groupId, String version) throws IOException { res.append(System.lineSeparator()).append(" id(\"io.quarkus\")").append(System.lineSeparator()); res.append("}"); } - if (!containsBOM(getQuarkusProject().getPlatformDescriptor().getBomGroupId(), - getQuarkusProject().getPlatformDescriptor().getBomArtifactId())) { + final ArtifactCoords bom = getQuarkusProject().getExtensionsCatalog().getBom(); + if (!containsBOM(bom.getGroupId(), bom.getArtifactId())) { res.append(System.lineSeparator()); res.append("dependencies {").append(System.lineSeparator()); res.append( @@ -91,6 +96,12 @@ void createSettingsContent(String artifactId) throws IOException { @Override void addDependencyInBuildFile(AppArtifactCoords coords) throws IOException { - AbstractKotlinGradleBuildFile.addDependencyInModel(getModel(), coords, false); + addDependencyInModel(getModel(), coords, false); + } + + static boolean addDependencyInModel(Model model, AppArtifactCoords coords, boolean managed) { + return AbstractGradleBuildFile.addDependencyInModel(model, + String.format(" implementation(%s)%n", + AbstractGradleBuildFile.createDependencyCoordinatesString(coords, managed, '"'))); } } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/MavenBuildFile.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/MavenBuildFile.java index 9a2d8b4828ddfa..06fe843d92377b 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/MavenBuildFile.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/buildfile/MavenBuildFile.java @@ -7,7 +7,7 @@ import io.quarkus.devtools.project.BuildTool; import io.quarkus.devtools.project.extensions.Extensions; import io.quarkus.maven.utilities.MojoUtils; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.registry.catalog.ExtensionCatalog; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -30,8 +30,8 @@ public class MavenBuildFile extends BuildFile { private final AtomicReference<Model> modelRef = new AtomicReference<>(); - public MavenBuildFile(final Path projectDirPath, final QuarkusPlatformDescriptor platformDescriptor) { - super(projectDirPath, platformDescriptor); + public MavenBuildFile(final Path projectDirPath, ExtensionCatalog catalog) { + super(projectDirPath, catalog); } @Override diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/codegen/ProjectGeneratorRegistry.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/codegen/ProjectGeneratorRegistry.java deleted file mode 100644 index 4090c600ef7b54..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/codegen/ProjectGeneratorRegistry.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.quarkus.devtools.project.codegen; - -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.ServiceLoader; -import java.util.concurrent.ConcurrentHashMap; - -/** - * @author <a href="claprun@redhat.com">Christophe Laprun</a> - */ -public class ProjectGeneratorRegistry { - - private static final Map<String, ProjectGenerator> generators = new ConcurrentHashMap<>(7); - private static final ProjectGeneratorRegistry INSTANCE = new ProjectGeneratorRegistry(); - - private ProjectGeneratorRegistry() { - loadGenerators(); - } - - public static ProjectGeneratorRegistry getInstance() { - return INSTANCE; - } - - public static ProjectGenerator get(String name) throws NoSuchElementException { - final ProjectGenerator generator = generators.get(name); - if (generator == null) { - throw new NoSuchElementException("Unknown generator: " + name); - } - - return generator; - } - - private static void register(ProjectGenerator generator) { - if (generator != null) { - generators.put(generator.getName(), generator); - } else { - throw new NullPointerException("Cannot register null generator"); - } - } - - private static void loadGenerators() { - ServiceLoader<ProjectGenerator> serviceLoader = ServiceLoader.load(ProjectGenerator.class); - serviceLoader.iterator().forEachRemaining(ProjectGeneratorRegistry::register); - } -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/codegen/rest/BasicRestProjectGenerator.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/codegen/rest/BasicRestProjectGenerator.java deleted file mode 100644 index bcd21bc2f7b2fa..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/codegen/rest/BasicRestProjectGenerator.java +++ /dev/null @@ -1,277 +0,0 @@ -package io.quarkus.devtools.project.codegen.rest; - -import static java.lang.String.format; - -import io.quarkus.devtools.commands.data.QuarkusCommandInvocation; -import io.quarkus.devtools.project.BuildTool; -import io.quarkus.devtools.project.codegen.ProjectGenerator; -import io.quarkus.devtools.project.codegen.SourceType; -import io.quarkus.devtools.project.codegen.writer.FileProjectWriter; -import io.quarkus.devtools.project.codegen.writer.ProjectWriter; -import io.quarkus.maven.utilities.MojoUtils; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.Map.Entry; - -public class BasicRestProjectGenerator implements ProjectGenerator { - - public static final String NAME = "basic-rest"; - - public BasicRestProjectGenerator() { - } - - @Override - public String getName() { - return NAME; - } - - @Override - public void generate(QuarkusCommandInvocation invocation) throws IOException { - final FileProjectWriter writer = new FileProjectWriter(invocation.getQuarkusProject().getProjectDirPath().toFile()); - writer.init(); - generate(writer, invocation); - } - - void generate(ProjectWriter writer, QuarkusCommandInvocation invocation) throws IOException { - final BasicRestProject project = new BasicRestProject(writer, invocation); - - project.initProject(); - project.setupContext(); - - project.createClasses(); - - project.createIndexPage(); - project.createDockerFiles(); - project.createDockerIgnore(); - project.createApplicationConfig(); - project.createReadme(); - - project.createGitIgnore(); - } - - private class BasicRestProject { - private QuarkusCommandInvocation invocation; - private String path = "/hello"; - private ProjectWriter writer; - private String srcMainPath; - private String testMainPath; - private String nativeTestMainPath; - private SourceType type; - - private BasicRestProject(final ProjectWriter writer, QuarkusCommandInvocation invocation) { - this.writer = writer; - this.invocation = invocation; - this.type = invocation.getValue(SOURCE_TYPE, SourceType.JAVA); - } - - @SuppressWarnings("unchecked") - private <T> T get(final String key, final T defaultValue) { - return invocation.getValue(key, defaultValue); - } - - private boolean initProject() throws IOException { - boolean newProject = initBuildTool(); - - path = get(RESOURCE_PATH, path); - - srcMainPath = writer.mkdirs(type.getSrcDir()); - testMainPath = writer.mkdirs(type.getTestSrcDir()); - // for gradle we want to place the native tests in under 'src/native-test/java' - // since gradle's idiomatic way of running integration tests is to create a new source set - switch (getBuildTool()) { - case GRADLE: - case GRADLE_KOTLIN_DSL: - nativeTestMainPath = writer.mkdirs(type.getTestSrcDir().replace("test", "native-test")); - break; - default: - nativeTestMainPath = testMainPath; - } - return newProject; - } - - private boolean initBuildTool() throws IOException { - BuildTool buildTool = getBuildTool(); - if (!invocation.hasValue(ADDITIONAL_GITIGNORE_ENTRIES)) { - invocation.setValue(ADDITIONAL_GITIGNORE_ENTRIES, buildTool.getGitIgnoreEntries()); - } - if (!invocation.hasValue(BUILD_DIRECTORY)) { - invocation.setValue(BUILD_DIRECTORY, buildTool.getBuildDirectory()); - } - if (!invocation.hasValue(MAVEN_REPOSITORIES)) { - invocation.setValue(MAVEN_REPOSITORIES, ""); - } - if (!invocation.hasValue(MAVEN_PLUGIN_REPOSITORIES)) { - invocation.setValue(MAVEN_PLUGIN_REPOSITORIES, ""); - } - - boolean newProject = !writer.exists(buildTool.getDependenciesFile()); - if (newProject) { - for (String buildFile : buildTool.getBuildFiles()) { - generate(type.getBuildFileResourceTemplate(getName(), buildFile), invocation, buildFile, buildFile); - } - } else { - String[] gav; - if (BuildTool.MAVEN.equals(buildTool)) { - ByteArrayInputStream buildFileInputStream = new ByteArrayInputStream( - writer.getContent(buildTool.getDependenciesFile())); - gav = MojoUtils.readGavFromPom(buildFileInputStream); - } else { - gav = new String[3]; - for (String buildFile : buildTool.getBuildFiles()) { - if (writer.exists(buildFile)) { - try (ByteArrayInputStream buildFileInputStream = new ByteArrayInputStream( - writer.getContent(buildFile))) { - gav = MojoUtils.readGavFromSettingsGradle(buildFileInputStream, gav); - } - } - } - } - if (gav[0] != null) { - invocation.setValue(PROJECT_GROUP_ID, gav[0]); - } - if (gav[1] != null) { - invocation.setValue(PROJECT_ARTIFACT_ID, gav[1]); - } - } - return newProject; - } - - private BuildTool getBuildTool() { - return invocation.getQuarkusProject().getBuildTool(); - } - - private void generate(final String templateName, QuarkusCommandInvocation invocation, final String outputFilePath, - final String resourceType) - throws IOException { - if (!writer.exists(outputFilePath)) { - String template = invocation.getPlatformDescriptor().getTemplate(templateName); - if (template == null) { - throw new IOException("Template resource is missing: " + templateName); - } - for (Entry<String, Object> e : invocation.getValues().entrySet()) { - if (e.getValue() instanceof String) { // Exclude null values (classname and path can be null) - template = template.replace(format("${%s}", e.getKey()), (String) e.getValue()); - } - } - - // do some nasty replacements for Java target if we want to generate Java 11 projects - if ("11".equals(invocation.getValue(JAVA_TARGET))) { - if (BuildTool.GRADLE.equals(invocation.getQuarkusProject().getBuildTool()) - || BuildTool.GRADLE_KOTLIN_DSL.equals(invocation.getQuarkusProject().getBuildTool())) { - template = template.replace("JavaVersion.VERSION_1_8", "JavaVersion.VERSION_11"); - } else { - template = template.replace("<maven.compiler.source>1.8</maven.compiler.source>", - "<maven.compiler.source>11</maven.compiler.source>"); - template = template.replace("<maven.compiler.target>1.8</maven.compiler.target>", - "<maven.compiler.target>11</maven.compiler.target>"); - // Kotlin - template = template.replace("<jvmTarget>1.8</jvmTarget>", "<jvmTarget>11</jvmTarget>"); - // Scala - // For now, we keep Java 8 as a target for Scala as we don't want to upgrade to 2.13 - // template = template.replace("<arg>-target:jvm-1.8</arg>", "<arg>-target:jvm-11</arg>"); - } - } - - writer.write(outputFilePath, template); - } - } - - private void createIndexPage() throws IOException { - // Generate index page - String resources = "src/main/resources/META-INF/resources"; - String index = writer.mkdirs(resources) + "/index.html"; - if (!writer.exists(index)) { - generate("templates/index.ftl", invocation, index, "welcome page"); - } - - } - - private void createDockerFiles() throws IOException { - String dockerRoot = "src/main/docker"; - String dockerRootDir = writer.mkdirs(dockerRoot); - generate("templates/dockerfile-native.ftl", invocation, dockerRootDir + "/Dockerfile.native", - "native docker file"); - generate("templates/dockerfile-jvm.ftl", invocation, dockerRootDir + "/Dockerfile.jvm", "jvm docker file"); - generate("templates/dockerfile-legacy-jar.ftl", invocation, dockerRootDir + "/Dockerfile.legacy-jar", - "jvm docker file"); - } - - private void createReadme() throws IOException { - String readme = writer.mkdirs("") + "README.md"; - BuildTool buildTool = getBuildTool(); - switch (buildTool) { - case MAVEN: - generate("templates/README.maven.ftl", invocation, readme, "read me"); - break; - case GRADLE: - case GRADLE_KOTLIN_DSL: - generate("templates/README.gradle.ftl", invocation, readme, "read me"); - break; - default: - throw new IllegalStateException("buildTool is none of Maven or Gradle"); - } - } - - private void createDockerIgnore() throws IOException { - String docker = writer.mkdirs("") + ".dockerignore"; - generate("templates/dockerignore.ftl", invocation, docker, "docker ignore"); - } - - private void createGitIgnore() throws IOException { - String gitignore = writer.mkdirs("") + ".gitignore"; - generate("templates/gitignore.ftl", invocation, gitignore, "git ignore"); - } - - private void createApplicationConfig() throws IOException { - String meta = "src/main/resources"; - String file = writer.mkdirs(meta) + "/application.properties"; - if (!writer.exists(file)) { - writer.write(file, "# Configuration file" + System.lineSeparator() + "# key = value"); - } - } - - private void setupContext() throws IOException { - if (invocation.getValue(CLASS_NAME) != null) { - String packageName = invocation.getStringValue(PACKAGE_NAME); - - if (packageName != null) { - String packageDir = srcMainPath + '/' + packageName.replace('.', '/'); - String originalTestMainPath = testMainPath; - String testPackageDir = testMainPath + '/' + packageName.replace('.', '/'); - srcMainPath = writer.mkdirs(packageDir); - testMainPath = writer.mkdirs(testPackageDir); - - if (!originalTestMainPath.equals(nativeTestMainPath)) { - String nativeTestPackageDir = nativeTestMainPath + '/' + packageName.replace('.', '/'); - nativeTestMainPath = writer.mkdirs(nativeTestPackageDir); - } else { - nativeTestMainPath = testMainPath; - } - - } else { - throw new NullPointerException("Need a non-null package name"); - } - } - } - - private void createClasses() throws IOException { - Object className = invocation.getValue(CLASS_NAME); - // If className is null we disable the generation of the JAX-RS resource. - if (className != null) { - String extension = type.getExtension(); - String classFile = srcMainPath + '/' + className + extension; - String testClassFile = testMainPath + '/' + className + "Test" + extension; - String itTestClassFile = nativeTestMainPath + '/' + "Native" + className + "IT" + extension; - String name = getName(); - String srcResourceTemplate = type.getSrcResourceTemplate(name); - Object isSpring = invocation.getValue(IS_SPRING); - if (isSpring != null && (Boolean) invocation.getValue(IS_SPRING).equals(Boolean.TRUE)) { - srcResourceTemplate = type.getSrcSpringControllerTemplate(name); - } - generate(srcResourceTemplate, invocation, classFile, "resource code"); - generate(type.getTestResourceTemplate(name), invocation, testClassFile, "test code"); - generate(type.getNativeTestResourceTemplate(name), invocation, itTestClassFile, "IT code"); - } - } - } -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/extensions/ExtensionManager.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/extensions/ExtensionManager.java index 6f0b7001944645..77148ae77bcaca 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/extensions/ExtensionManager.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/extensions/ExtensionManager.java @@ -2,7 +2,6 @@ import io.quarkus.bootstrap.model.AppArtifactCoords; import io.quarkus.bootstrap.model.AppArtifactKey; -import io.quarkus.dependencies.Extension; import io.quarkus.devtools.project.BuildTool; import java.io.IOException; import java.util.Collection; diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/extensions/Extensions.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/extensions/Extensions.java index b6039f608c3aaa..f6643cd4d9f331 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/extensions/Extensions.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/extensions/Extensions.java @@ -2,8 +2,8 @@ import io.quarkus.bootstrap.model.AppArtifactCoords; import io.quarkus.bootstrap.model.AppArtifactKey; -import io.quarkus.dependencies.Extension; -import java.util.List; +import io.quarkus.registry.catalog.Extension; +import java.util.Collection; import java.util.Objects; import java.util.Optional; import org.apache.maven.model.Dependency; @@ -13,7 +13,10 @@ private Extensions() { } public static AppArtifactKey toKey(final Extension extension) { - return toKey(extension.toDependency(false)); + return new AppArtifactKey(extension.getArtifact().getGroupId(), + extension.getArtifact().getArtifactId(), + extension.getArtifact().getClassifier(), + extension.getArtifact().getType()); } public static AppArtifactKey toKey(final Dependency dependency) { @@ -21,7 +24,7 @@ public static AppArtifactKey toKey(final Dependency dependency) { dependency.getType()); } - public static Optional<Extension> findInList(List<Extension> list, final AppArtifactKey key) { + public static Optional<Extension> findInList(Collection<Extension> list, final AppArtifactKey key) { return list.stream().filter(e -> Objects.equals(toCoords(e).getKey(), key)).findFirst(); } @@ -30,7 +33,11 @@ public static AppArtifactCoords toCoords(final AppArtifactKey k, final String ve } public static AppArtifactCoords toCoords(final Extension e) { - return toCoords(e.toDependency(false)); + return new AppArtifactCoords(e.getArtifact().getGroupId(), + e.getArtifact().getArtifactId(), + e.getArtifact().getClassifier(), + e.getArtifact().getType(), + e.getArtifact().getVersion()); } public static AppArtifactCoords toCoords(final Dependency d, final String overrideVersion) { @@ -53,7 +60,7 @@ public static String toGA(AppArtifactKey c) { } public static String toGA(Extension e) { - return e.getGroupId() + ":" + e.getArtifactId(); + return e.getArtifact().getGroupId() + ":" + e.getArtifact().getArtifactId(); } public static AppArtifactCoords stripVersion(final AppArtifactCoords coords) { diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/ProjectPlatformDescriptorJsonUtil.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/ProjectPlatformDescriptorJsonUtil.java new file mode 100644 index 00000000000000..2dafb527957a7c --- /dev/null +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/ProjectPlatformDescriptorJsonUtil.java @@ -0,0 +1,107 @@ +package io.quarkus.platform.descriptor; + +import io.quarkus.bootstrap.BootstrapConstants; +import io.quarkus.bootstrap.model.AppArtifact; +import io.quarkus.bootstrap.model.AppArtifactCoords; +import io.quarkus.bootstrap.model.AppArtifactKey; +import io.quarkus.bootstrap.resolver.AppModelResolver; +import io.quarkus.bootstrap.resolver.AppModelResolverException; +import io.quarkus.maven.ArtifactKey; +import io.quarkus.registry.catalog.Category; +import io.quarkus.registry.catalog.Extension; +import io.quarkus.registry.catalog.ExtensionOrigin; +import io.quarkus.registry.catalog.json.JsonCatalogMapperHelper; +import io.quarkus.registry.catalog.json.JsonExtensionCatalog; +import io.quarkus.registry.catalog.json.JsonExtensionOrigin; +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class ProjectPlatformDescriptorJsonUtil { + + public static JsonExtensionCatalog resolveCatalog(AppModelResolver resolver, List<AppArtifact> depConstraints) + throws AppModelResolverException { + final List<JsonExtensionCatalog> platforms = new ArrayList<>(2); + final Set<AppArtifactKey> processedPlatforms = new HashSet<>(); + for (int i = depConstraints.size() - 1; i >= 0; --i) { + final AppArtifact artifact = depConstraints.get(i); + if (!artifact.getArtifactId().endsWith(BootstrapConstants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX) + && !artifact.getType().equals("json")) { + continue; + } + if (!processedPlatforms.add(artifact.getKey())) { + continue; + } + final Path json = resolver.resolve(artifact); + final JsonExtensionCatalog platform; + try { + platform = JsonCatalogMapperHelper.deserialize(json, JsonExtensionCatalog.class); + } catch (IOException e) { + throw new AppModelResolverException("Failed to deserialize a platform descriptor from " + json, e); + } + platform.getDerivedFrom().forEach(o -> processedPlatforms.add(AppArtifactCoords.fromString(o.getId()).getKey())); + platforms.add(platform); + } + if (platforms.isEmpty()) { + return null; + } + + final List<ExtensionOrigin> derivedFrom = new ArrayList<>(); + final List<Extension> extensions = new ArrayList<>(); + final Set<ArtifactKey> extensionKeys = new HashSet<>(); + final List<Category> categories = new ArrayList<>(); + final Set<String> categoryIds = new HashSet<>(); + final Map<String, Object> metadata = new HashMap<>(); + + final JsonExtensionCatalog catalog = new JsonExtensionCatalog(); + catalog.setPlatform(false); + catalog.setDerivedFrom(derivedFrom); + catalog.setExtensions(extensions); + catalog.setCategories(categories); + catalog.setMetadata(metadata); + + final JsonExtensionCatalog dominatingPlatform = platforms.get(0); + catalog.setQuarkusCoreVersion(dominatingPlatform.getQuarkusCoreVersion()); + catalog.setUpstreamQuarkusCoreVersion(dominatingPlatform.getUpstreamQuarkusCoreVersion()); + + for (int i = platforms.size() - 1; i >= 0; --i) { + final JsonExtensionCatalog platform = platforms.get(i); + if (platform.getBom() != null) { + catalog.setBom(platform.getBom()); + } + final JsonExtensionOrigin origin = new JsonExtensionOrigin(); + origin.setId(platform.getId()); + origin.setPlatform(platform.isPlatform()); + origin.setBom(platform.getBom()); + derivedFrom.add(origin); + + for (Extension e : platform.getExtensions()) { + if (extensionKeys.add(e.getArtifact().getKey())) { + extensions.add(e); + } + } + + if (platform.getCategories().isEmpty()) { + for (Category c : platform.getCategories()) { + if (categoryIds.add(c.getId())) { + categories.add(c); + } + } + } + + if (!platform.getMetadata().isEmpty()) { + for (Map.Entry<String, Object> entry : platform.getMetadata().entrySet()) { + if (!metadata.containsKey(entry.getKey())) { + metadata.put(entry.getKey(), entry.getValue()); + } + } + } + } + return catalog; + } +} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ArtifactResolver.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ArtifactResolver.java deleted file mode 100644 index 34a20cb09b028c..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ArtifactResolver.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.quarkus.platform.descriptor.loader.json; - -import io.quarkus.bootstrap.resolver.AppModelResolverException; -import java.nio.file.Path; -import java.util.function.Function; - -public interface ArtifactResolver { - - default <T> T process(String groupId, String artifactId, String version, Function<Path, T> processor) - throws AppModelResolverException { - return process(groupId, artifactId, null, "jar", version, processor); - } - - <T> T process(String groupId, String artifactId, String classifier, String type, String version, - Function<Path, T> processor) throws AppModelResolverException; -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ClassPathResourceLoader.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ClassPathResourceLoader.java index 08e95c9f035202..7746ffc19c3362 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ClassPathResourceLoader.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ClassPathResourceLoader.java @@ -1,7 +1,5 @@ package io.quarkus.platform.descriptor.loader.json; -import io.quarkus.platform.descriptor.ResourceInputStreamConsumer; -import io.quarkus.platform.descriptor.ResourcePathConsumer; import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/DirectoryResourceLoader.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/DirectoryResourceLoader.java index cbadf703b792be..e59700228f3f13 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/DirectoryResourceLoader.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/DirectoryResourceLoader.java @@ -1,6 +1,5 @@ package io.quarkus.platform.descriptor.loader.json; -import io.quarkus.platform.descriptor.ResourcePathConsumer; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/QuarkusJsonPlatformDescriptorLoader.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/QuarkusJsonPlatformDescriptorLoader.java deleted file mode 100644 index 812f31dc1c185b..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/QuarkusJsonPlatformDescriptorLoader.java +++ /dev/null @@ -1,9 +0,0 @@ -package io.quarkus.platform.descriptor.loader.json; - -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.descriptor.loader.QuarkusPlatformDescriptorLoader; - -public interface QuarkusJsonPlatformDescriptorLoader<D extends QuarkusPlatformDescriptor> - extends QuarkusPlatformDescriptorLoader<D, QuarkusJsonPlatformDescriptorLoaderContext> { - -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/QuarkusJsonPlatformDescriptorLoaderContext.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/QuarkusJsonPlatformDescriptorLoaderContext.java deleted file mode 100644 index 56e316c529bf33..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/QuarkusJsonPlatformDescriptorLoaderContext.java +++ /dev/null @@ -1,43 +0,0 @@ -package io.quarkus.platform.descriptor.loader.json; - -import io.quarkus.devtools.messagewriter.MessageWriter; -import io.quarkus.platform.descriptor.loader.QuarkusPlatformDescriptorLoaderContext; -import java.io.InputStream; -import java.util.function.Function; - -public abstract class QuarkusJsonPlatformDescriptorLoaderContext implements QuarkusPlatformDescriptorLoaderContext { - - protected final MessageWriter log; - protected final ArtifactResolver artifactResolver; - protected final ResourceLoader resourceLoader; - - public QuarkusJsonPlatformDescriptorLoaderContext(ArtifactResolver artifactResolver) { - this(artifactResolver, MessageWriter.info()); - } - - public QuarkusJsonPlatformDescriptorLoaderContext(ArtifactResolver artifactResolver, MessageWriter log) { - this(artifactResolver, new ClassPathResourceLoader(Thread.currentThread().getContextClassLoader()), log); - } - - public QuarkusJsonPlatformDescriptorLoaderContext(ArtifactResolver artifactResolver, ResourceLoader resourceLoader, - MessageWriter log) { - this.log = log; - this.artifactResolver = artifactResolver; - this.resourceLoader = resourceLoader; - } - - public abstract <T> T parseJson(Function<InputStream, T> parser); - - @Override - public MessageWriter getMessageWriter() { - return log; - } - - public ArtifactResolver getArtifactResolver() { - return artifactResolver; - } - - public ResourceLoader getResourceLoader() { - return resourceLoader; - } -} diff --git a/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/platform/descriptor/ResourceInputStreamConsumer.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ResourceInputStreamConsumer.java similarity index 75% rename from independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/platform/descriptor/ResourceInputStreamConsumer.java rename to independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ResourceInputStreamConsumer.java index 4898146a6fa52f..5bd29649a6d58c 100644 --- a/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/platform/descriptor/ResourceInputStreamConsumer.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ResourceInputStreamConsumer.java @@ -1,4 +1,4 @@ -package io.quarkus.platform.descriptor; +package io.quarkus.platform.descriptor.loader.json; import java.io.IOException; import java.io.InputStream; diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ResourceLoader.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ResourceLoader.java index eca2fa1a54d4b3..910ae860ea8747 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ResourceLoader.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ResourceLoader.java @@ -1,7 +1,5 @@ package io.quarkus.platform.descriptor.loader.json; -import io.quarkus.platform.descriptor.ResourceInputStreamConsumer; -import io.quarkus.platform.descriptor.ResourcePathConsumer; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; diff --git a/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/platform/descriptor/ResourcePathConsumer.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ResourcePathConsumer.java similarity index 73% rename from independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/platform/descriptor/ResourcePathConsumer.java rename to independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ResourcePathConsumer.java index 88ccd84c238583..cacb282ffbcc14 100644 --- a/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/platform/descriptor/ResourcePathConsumer.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ResourcePathConsumer.java @@ -1,4 +1,4 @@ -package io.quarkus.platform.descriptor; +package io.quarkus.platform.descriptor.loader.json; import java.io.IOException; import java.nio.file.Path; diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ZipResourceLoader.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ZipResourceLoader.java index af60f9d9226f7c..8c16537ada6483 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ZipResourceLoader.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/descriptor/loader/json/ZipResourceLoader.java @@ -1,6 +1,5 @@ package io.quarkus.platform.descriptor.loader.json; -import io.quarkus.platform.descriptor.ResourcePathConsumer; import java.io.IOException; import java.nio.file.FileSystem; import java.nio.file.FileSystems; diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/tools/ToolsUtils.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/tools/ToolsUtils.java index a5c3127293450a..82a8c02a45aee8 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/tools/ToolsUtils.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/tools/ToolsUtils.java @@ -1,8 +1,25 @@ package io.quarkus.platform.tools; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.bootstrap.BootstrapConstants; +import io.quarkus.bootstrap.model.AppArtifact; +import io.quarkus.bootstrap.resolver.AppModelResolver; +import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver; +import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; +import io.quarkus.devtools.messagewriter.MessageWriter; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.catalog.ExtensionCatalog; +import io.quarkus.registry.catalog.json.JsonCatalogMapperHelper; +import io.quarkus.registry.catalog.json.JsonCatalogMerger; +import io.quarkus.registry.catalog.json.JsonExtensionCatalog; import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; import java.util.Properties; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.DefaultArtifact; public class ToolsUtils { @@ -42,17 +59,76 @@ public static String dotJoin(String... parts) { return buf.toString(); } - public static Properties readQuarkusProperties(QuarkusPlatformDescriptor platformDescr) { - final Properties properties; + public static ExtensionCatalog resolvePlatformDescriptorDirectly(String bomGroupId, String bomArtifactId, String bomVersion, + MavenArtifactResolver artifactResolver, MessageWriter log) { + // TODO remove this method once we have the registry service available + if (bomVersion == null) { + throw new IllegalArgumentException("BOM version was not provided"); + } + Artifact catalogCoords = new DefaultArtifact( + bomGroupId == null ? "io.quarkus" : bomGroupId, + (bomArtifactId == null ? "quarkus-universe-bom" : bomArtifactId) + + BootstrapConstants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX, + bomVersion, "json", bomVersion); + Path platformJson = null; + try { + log.debug("Resolving platform descriptor %s", catalogCoords); + platformJson = artifactResolver.resolve(catalogCoords).getArtifact().getFile().toPath(); + } catch (Exception e) { + if (bomArtifactId == null && catalogCoords.getArtifactId().startsWith("quarkus-universe-bom")) { + catalogCoords = new DefaultArtifact( + catalogCoords.getGroupId(), + "quarkus-bom" + BootstrapConstants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX, + catalogCoords.getClassifier(), catalogCoords.getExtension(), catalogCoords.getVersion()); + try { + log.debug("Resolving platform descriptor %s", catalogCoords); + platformJson = artifactResolver.resolve(catalogCoords).getArtifact().getFile().toPath(); + } catch (Exception e2) { + } + } + if (platformJson == null) { + throw new RuntimeException("Failed to resolve the default platform JSON descriptor", e); + } + } try { - properties = platformDescr.loadResource("quarkus.properties", is -> { - final Properties props = new Properties(); - props.load(is); - return props; - }); + return JsonCatalogMapperHelper.deserialize(platformJson, JsonExtensionCatalog.class); } catch (IOException e) { - throw new IllegalStateException("Failed to read quarkus.properties", e); + throw new RuntimeException("Failed to deserialize extension catalog " + platformJson, e); + } + } + + public static ExtensionCatalog mergePlatforms(List<ArtifactCoords> platforms, MavenArtifactResolver artifactResolver) { + // TODO remove this method once we have the registry service available + return mergePlatforms(platforms, new BootstrapAppModelResolver(artifactResolver)); + } + + public static ExtensionCatalog mergePlatforms(List<ArtifactCoords> platforms, AppModelResolver artifactResolver) { + // TODO remove this method once we have the registry service available + List<ExtensionCatalog> catalogs = new ArrayList<>(platforms.size()); + for (ArtifactCoords platform : platforms) { + final Path json; + try { + json = artifactResolver.resolve(new AppArtifact(platform.getGroupId(), platform.getArtifactId(), + platform.getClassifier(), platform.getType(), platform.getVersion())); + } catch (Exception e) { + throw new RuntimeException("Failed to resolve platform descriptor " + platform, e); + } + try { + catalogs.add(JsonCatalogMapperHelper.deserialize(json, JsonExtensionCatalog.class)); + } catch (IOException e) { + throw new RuntimeException("Failed to deserialize platform descriptor " + json, e); + } } + return JsonCatalogMerger.merge(catalogs); + } + + @SuppressWarnings("unchecked") + public static Properties readQuarkusProperties(ExtensionCatalog catalog) { + Map<Object, Object> map = (Map<Object, Object>) catalog.getMetadata().getOrDefault("project", Collections.emptyMap()); + map = (Map<Object, Object>) map.getOrDefault("properties", Collections.emptyMap()); + final Properties properties = new Properties(); + map.entrySet().forEach( + e -> properties.setProperty(e.getKey().toString(), e.getValue() == null ? null : e.getValue().toString())); return properties; } diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/tools/config/QuarkusPlatformConfig.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/tools/config/QuarkusPlatformConfig.java deleted file mode 100644 index 30517d22ddc31b..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/platform/tools/config/QuarkusPlatformConfig.java +++ /dev/null @@ -1,175 +0,0 @@ -package io.quarkus.platform.tools.config; - -import io.quarkus.devtools.messagewriter.MessageWriter; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.descriptor.loader.QuarkusPlatformDescriptorLoader; -import io.quarkus.platform.descriptor.loader.QuarkusPlatformDescriptorLoaderContext; -import java.util.Iterator; -import java.util.ServiceLoader; -import java.util.concurrent.atomic.AtomicReference; - -public class QuarkusPlatformConfig { - - public static class Builder { - - private int type = STANDALONE; - private MessageWriter log; - private QuarkusPlatformDescriptor platformDescr; - - private Builder(int type) { - if (type == GLOBAL) { - assertNoGlobalConfig(); - } else if (type == THREAD_LOCAL) { - assertNoThreadLocalConfig(); - } - this.type = type; - } - - public Builder setMessageWriter(MessageWriter msgWriter) { - this.log = msgWriter; - return this; - } - - private MessageWriter getMessageWriter() { - return log == null ? log = MessageWriter.info() : log; - } - - public Builder setPlatformDescriptor(QuarkusPlatformDescriptor platformDescr) { - this.platformDescr = platformDescr; - return this; - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - private QuarkusPlatformDescriptor getPlatformDescriptor() { - if (platformDescr != null) { - return platformDescr; - } - - final Iterator<QuarkusPlatformDescriptorLoader> i = ServiceLoader.load(QuarkusPlatformDescriptorLoader.class) - .iterator(); - if (!i.hasNext()) { - throw new IllegalStateException("Failed to locate an implementation of " - + QuarkusPlatformDescriptorLoader.class.getName() + " on the classpath"); - } - final QuarkusPlatformDescriptorLoader<QuarkusPlatformDescriptor, QuarkusPlatformDescriptorLoaderContext> dl = i - .next(); - if (i.hasNext()) { - final StringBuilder buf = new StringBuilder(); - buf.append("Found multiple implementations of ").append(QuarkusPlatformDescriptorLoader.class.getName()) - .append("on the classpath: ").append(dl.getClass().getName()); - while (i.hasNext()) { - buf.append(", ").append(i.next().getClass().getName()); - } - throw new IllegalStateException(buf.toString()); - } - return platformDescr = dl.load(new QuarkusPlatformDescriptorLoaderContext() { - @Override - public MessageWriter getMessageWriter() { - return Builder.this.getMessageWriter(); - } - }); - } - - public QuarkusPlatformConfig build() { - return new QuarkusPlatformConfig(this); - } - } - - public static Builder builder() { - return new Builder(STANDALONE); - } - - /** - * This hopefully will be a temporary way of providing global default config - * by creating a builder that will create a config instance which will serve - * as the global default config. - */ - public static Builder defaultConfigBuilder() { - return new Builder(GLOBAL); - } - - /** - * This hopefully will be a temporary way of providing global default config - * by creating a builder that will create a config instance which will serve - * as the global default config. - */ - public static Builder threadLocalConfigBuilder() { - return new Builder(THREAD_LOCAL); - } - - public static QuarkusPlatformConfig newInstance() { - return builder().build(); - } - - public static synchronized QuarkusPlatformConfig getGlobalDefault() { - final QuarkusPlatformConfig c = globalConfig.get(); - if (c != null) { - return c; - } - return defaultConfigBuilder().build(); - } - - public static boolean hasGlobalDefault() { - return globalConfig.get() != null; - } - - public static QuarkusPlatformConfig getThreadLocal() { - final QuarkusPlatformConfig c = threadLocalConfig.get(); - if (c != null) { - return c; - } - return threadLocalConfigBuilder().build(); - } - - public static boolean hasThreadLocal() { - return threadLocalConfig.get() != null; - } - - public static void clearThreadLocal() { - threadLocalConfig.remove(); - } - - private static void assertNoGlobalConfig() { - if (globalConfig.get() != null) { - throw new IllegalStateException( - "The global instance of " + QuarkusPlatformConfig.class.getName() + " has already been initialized"); - } - } - - private static void assertNoThreadLocalConfig() { - if (threadLocalConfig.get() != null) { - throw new IllegalStateException( - "The thread local instance of " + QuarkusPlatformConfig.class.getName() + " has already been initialized"); - } - } - - private static final int STANDALONE = 0; - private static final int GLOBAL = 1; - private static final int THREAD_LOCAL = 2; - - private static final AtomicReference<QuarkusPlatformConfig> globalConfig = new AtomicReference<>(); - private static final ThreadLocal<QuarkusPlatformConfig> threadLocalConfig = new ThreadLocal<>(); - - private final MessageWriter log; - private final QuarkusPlatformDescriptor platformDescr; - - private QuarkusPlatformConfig(Builder builder) { - this.log = builder.getMessageWriter(); - this.platformDescr = builder.getPlatformDescriptor(); - if (builder.type == GLOBAL) { - assertNoGlobalConfig(); - globalConfig.set(this); - } else if (builder.type == THREAD_LOCAL) { - assertNoThreadLocalConfig(); - threadLocalConfig.set(this); - } - } - - public MessageWriter getMessageWriter() { - return log; - } - - public QuarkusPlatformDescriptor getPlatformDescriptor() { - return platformDescr; - } -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/DefaultExtensionRegistry.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/DefaultExtensionRegistry.java deleted file mode 100644 index 7b2aff278e8a7f..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/DefaultExtensionRegistry.java +++ /dev/null @@ -1,212 +0,0 @@ -package io.quarkus.registry; - -import io.quarkus.bootstrap.model.AppArtifactCoords; -import io.quarkus.bootstrap.model.AppArtifactKey; -import io.quarkus.dependencies.Extension; -import io.quarkus.dependencies.ExtensionPredicate; -import io.quarkus.devtools.project.extensions.ExtensionInstallPlan; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.registry.builder.RegistryBuilder; -import io.quarkus.registry.builder.URLRegistryBuilder; -import io.quarkus.registry.model.ArtifactKey; -import io.quarkus.registry.model.Extension.ExtensionRelease; -import io.quarkus.registry.model.Registry; -import java.io.IOException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; -import org.apache.commons.lang3.StringUtils; -import org.apache.maven.artifact.versioning.ComparableVersion; -import org.immutables.value.Value; - -/** - * This {@link ExtensionRegistry} implementation uses in-memory {@link Registry} - * objects to query the data. - */ -public class DefaultExtensionRegistry implements ExtensionRegistry { - - private final Registry registry; - - /** - * Create a {@link DefaultExtensionRegistry} out of a {@link Collection} of {@link URL}s - * - * @param urls urls used to lookup this registry - * @return a {@link DefaultExtensionRegistry} instance - * @throws IOException if any IO error occurs while reading each URL contents - */ - public static DefaultExtensionRegistry fromURLs(Collection<URL> urls) throws IOException { - Registry registry = new URLRegistryBuilder() - .addURLs(urls) - .build(); - return new DefaultExtensionRegistry(registry); - } - - /** - * Create a {@link DefaultExtensionRegistry} from a single {@link QuarkusPlatformDescriptor} - * - * @param platform the single platform - * @return a {@link DefaultExtensionRegistry} instance - */ - public static DefaultExtensionRegistry fromPlatform(QuarkusPlatformDescriptor platform) { - RegistryBuilder builder = new RegistryBuilder(); - builder.visitPlatform(platform); - return new DefaultExtensionRegistry(builder.build()); - } - - public DefaultExtensionRegistry(Registry registry) { - this.registry = Objects.requireNonNull(registry, "Registry cannot be null"); - } - - @Override - public Set<String> getQuarkusCoreVersions() { - return registry.getCoreVersions().keySet().stream().map(ComparableVersion::toString).collect( - Collectors.toCollection(LinkedHashSet::new)); - } - - @Override - public Set<Extension> getExtensionsByCoreVersion(String version) { - return list(version, ""); - } - - @Override - public Set<Extension> list(String quarkusCore, String keyword) { - return listInternalExtensions(quarkusCore, keyword) - .stream() - .map(this::toQuarkusExtension) - .sorted(Comparator.comparing(Extension::getArtifactId)) - .collect(Collectors.toCollection(LinkedHashSet::new)); - } - - @Override - public ExtensionInstallPlan planInstallation(String quarkusCore, Collection<String> keywords) { - ExtensionInstallPlan.Builder builder = ExtensionInstallPlan.builder(); - boolean multipleKeywords = keywords.size() > 1; - for (String keyword : keywords) { - int countColons = StringUtils.countMatches(keyword, ":"); - // Check if it's just groupId:artifactId - if (countColons == 1) { - AppArtifactKey artifactKey = AppArtifactKey.fromString(keyword); - builder.addManagedExtension(new AppArtifactCoords(artifactKey, null)); - continue; - } else if (countColons > 1) { - // it's a gav - builder.addIndependentExtension(AppArtifactCoords.fromString(keyword)); - continue; - } - List<ExtensionReleaseTuple> tuples = listInternalExtensions(quarkusCore, keyword); - if (tuples.size() != 1 && multipleKeywords) { - // No extension found for this keyword. Return empty immediately - return ExtensionInstallPlan.EMPTY; - } - // If it's a pattern allow multiple results - // See https://github.com/quarkusio/quarkus/issues/11086#issuecomment-666360783 - else if (tuples.size() > 1 && !ExtensionPredicate.isPattern(keyword)) { - throw new MultipleExtensionsFoundException(keyword, - tuples.stream().map(this::toQuarkusExtension).collect(Collectors.toList())); - } - for (ExtensionReleaseTuple tuple : tuples) { - ArtifactKey id = tuple.getExtension().getId(); - String groupId = id.getGroupId(); - String artifactId = id.getArtifactId(); - String version = tuple.getRelease().getRelease().getVersion(); - AppArtifactCoords extensionCoords = new AppArtifactCoords(groupId, artifactId, version); - List<AppArtifactCoords> platformCoords = tuple.getRelease().getPlatforms() - .stream() - .map(c -> new AppArtifactCoords( - c.getCoords().getId().getGroupId(), - c.getCoords().getId().getArtifactId(), - "pom", - c.getCoords().getVersion())) - .collect(Collectors.toList()); - if (platformCoords.isEmpty()) { - builder.addIndependentExtension(extensionCoords); - } else { - builder.addManagedExtension(extensionCoords); - for (AppArtifactCoords platformCoord : platformCoords) { - builder.addPlatform(platformCoord); - } - } - } - } - return builder.build(); - } - - private List<ExtensionReleaseTuple> listInternalExtensions(String quarkusCore, String keyword) { - List<ExtensionReleaseTuple> result = new ArrayList<>(); - ExtensionPredicate predicate = null; - if (keyword != null && !keyword.isEmpty()) { - predicate = new ExtensionPredicate(keyword); - } - for (io.quarkus.registry.model.Extension extension : registry.getExtensions()) { - for (ExtensionRelease extensionRelease : extension.getReleases()) { - if (quarkusCore.equals(extensionRelease.getRelease().getQuarkusCore())) { - ExtensionReleaseTuple tuple = ExtensionReleaseTuple.builder().extension(extension) - .release(extensionRelease).build(); - // If no filter is defined, just return the tuple - if (predicate == null) { - result.add(tuple); - } else { - Extension quarkusExtension = toQuarkusExtension(tuple); - // If there is an exact match, return only this - if (predicate.isExactMatch(quarkusExtension)) { - return Collections.singletonList(tuple); - } else if (predicate.test(quarkusExtension)) { - result.add(tuple); - } - } - break; - } - } - } - return result; - } - - private Extension toQuarkusExtension(ExtensionReleaseTuple tuple) { - io.quarkus.registry.model.Extension extension = tuple.getExtension(); - ExtensionRelease tupleRelease = tuple.getRelease(); - // Platforms may have metadata overriding the extension metadata - Map<String, Object> metadata = new HashMap<>(extension.getMetadata()); - tupleRelease.getPlatforms().stream() - .map(io.quarkus.registry.model.Extension.ExtensionPlatformRelease::getMetadata) - .findFirst() - .ifPresent(metadata::putAll); - ArtifactKey id = extension.getId(); - return new Extension() - .setGroupId(id.getGroupId()) - .setArtifactId(id.getArtifactId()) - .setVersion(tupleRelease.getRelease().getVersion()) - .setName(extension.getName()) - .setDescription(extension.getDescription()) - .setMetadata(metadata); - } - - /** - * Used in tests - */ - public Registry getRegistry() { - return registry; - } - - /** - * This exists only because ExtensionRelease does not accept a back reference to Extension - */ - @Value.Immutable - interface ExtensionReleaseTuple { - io.quarkus.registry.model.Extension getExtension(); - - ExtensionRelease getRelease(); - - static ImmutableExtensionReleaseTuple.Builder builder() { - return ImmutableExtensionReleaseTuple.builder(); - } - } -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/ExtensionRegistry.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/ExtensionRegistry.java deleted file mode 100644 index a25dfb51729400..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/ExtensionRegistry.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.quarkus.registry; - -import io.quarkus.dependencies.Extension; -import io.quarkus.devtools.project.extensions.ExtensionInstallPlan; -import java.util.Collection; - -public interface ExtensionRegistry { - - // Query methods - Collection<String> getQuarkusCoreVersions(); - - Collection<Extension> getExtensionsByCoreVersion(String version); - - /** - * Return the set of extensions that matches a given keyword - * - * @param quarkusCore the quarkus core this extension supports - * @param keyword the keyword to search - * @return a set of {@link Extension} objects or an empty set if not found - */ - Collection<Extension> list(String quarkusCore, String keyword); - - /** - * What platforms and extensions do I need to add to my build descriptor? - * This method looks up the registry and provides a {@link ExtensionInstallPlan} containing this information. - * - * @param quarkusCore the quarkus core this extension supports - * @param keywords the keywords to lookup - * @return a {@link ExtensionInstallPlan} an object representing the necessary data to be added to a build descriptor - */ - ExtensionInstallPlan planInstallation(String quarkusCore, Collection<String> keywords); - -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/RepositoryIndexer.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/RepositoryIndexer.java deleted file mode 100644 index 000dd6dd86ab8c..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/RepositoryIndexer.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.quarkus.registry; - -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.registry.catalog.model.Extension; -import io.quarkus.registry.catalog.model.Platform; -import io.quarkus.registry.catalog.model.Repository; -import io.quarkus.registry.catalog.spi.ArtifactResolver; -import io.quarkus.registry.catalog.spi.IndexVisitor; -import io.quarkus.registry.model.Release; -import java.io.IOException; -import java.util.Objects; - -/** - * Indexes a repository - */ -public class RepositoryIndexer { - - private final ArtifactResolver artifactResolver; - - public RepositoryIndexer(ArtifactResolver artifactResolver) { - this.artifactResolver = Objects.requireNonNull(artifactResolver, "Resolver cannot be null"); - } - - public void index(Repository repository, IndexVisitor visitor) throws IOException { - // Index Platforms - for (Platform platform : repository.getPlatforms()) { - for (Release release : platform.getReleases()) { - QuarkusPlatformDescriptor descriptor = artifactResolver.resolvePlatform(platform, release); - if (descriptor != null) { - visitor.visitPlatform(descriptor); - } - } - } - - // Index extensions - for (Extension extension : repository.getIndividualExtensions()) { - for (Release release : extension.getReleases()) { - io.quarkus.dependencies.Extension ext = artifactResolver.resolveExtension(extension, release); - if (ext != null) { - visitor.visitExtension(ext, release.getQuarkusCore()); - } - } - } - } -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/builder/ExtensionRegistryBuilder.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/builder/ExtensionRegistryBuilder.java deleted file mode 100644 index 8e1b62248fd408..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/builder/ExtensionRegistryBuilder.java +++ /dev/null @@ -1,48 +0,0 @@ -package io.quarkus.registry.builder; - -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.registry.DefaultExtensionRegistry; -import io.quarkus.registry.ExtensionRegistry; -import io.quarkus.registry.catalog.model.Extension; -import io.quarkus.registry.catalog.model.Platform; -import io.quarkus.registry.catalog.spi.ArtifactResolver; -import io.quarkus.registry.model.Registry; -import io.quarkus.registry.model.Release; -import java.io.IOException; - -/** - * Builds an {@link ExtensionRegistry} given the platforms and extensions resolved by the - * {@link ArtifactResolver} - */ -public class ExtensionRegistryBuilder { - - private final ArtifactResolver artifactResolver; - private final RegistryBuilder registryBuilder = new RegistryBuilder(); - - public ExtensionRegistryBuilder(ArtifactResolver artifactResolver) { - this.artifactResolver = artifactResolver; - } - - public ExtensionRegistryBuilder addPlatform(String groupId, String artifactId, String version) throws IOException { - Platform platform = Platform.builder().groupId(groupId).artifactId(artifactId).build(); - Release release = Release.builder().version(version).build(); - QuarkusPlatformDescriptor descriptor = artifactResolver.resolvePlatform(platform, release); - registryBuilder.visitPlatform(descriptor); - return this; - } - - public ExtensionRegistryBuilder addExtension(String groupId, String artifactId, String version, String quarkusCore) - throws IOException { - Extension extension = Extension.builder().groupId(groupId).artifactId(artifactId).build(); - Release release = Release.builder().version(version).build(); - io.quarkus.dependencies.Extension ext = artifactResolver.resolveExtension(extension, release); - registryBuilder.visitExtension(ext, quarkusCore); - return this; - } - - public ExtensionRegistry build() { - Registry registry = registryBuilder.build(); - return new DefaultExtensionRegistry(registry); - } - -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/builder/RegistryBuilder.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/builder/RegistryBuilder.java deleted file mode 100644 index 4eaeb8524b3674..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/builder/RegistryBuilder.java +++ /dev/null @@ -1,122 +0,0 @@ -package io.quarkus.registry.builder; - -import io.quarkus.dependencies.Extension; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.registry.catalog.spi.IndexVisitor; -import io.quarkus.registry.model.ArtifactCoords; -import io.quarkus.registry.model.ArtifactKey; -import io.quarkus.registry.model.Extension.ExtensionPlatformRelease; -import io.quarkus.registry.model.ImmutableArtifactCoords; -import io.quarkus.registry.model.ImmutableArtifactKey; -import io.quarkus.registry.model.ImmutableExtensionPlatformRelease; -import io.quarkus.registry.model.ImmutableRegistry; -import io.quarkus.registry.model.ModifiableExtension; -import io.quarkus.registry.model.ModifiableExtensionRelease; -import io.quarkus.registry.model.ModifiablePlatform; -import io.quarkus.registry.model.Registry; -import io.quarkus.registry.model.Release; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Objects; -import org.apache.maven.artifact.versioning.ComparableVersion; -import org.immutables.value.Value; - -public class RegistryBuilder implements IndexVisitor { - - private final Map<ArtifactKey, ModifiablePlatform> platforms = new LinkedHashMap<>(); - - private final Map<ArtifactKey, ModifiableExtension> extensions = new LinkedHashMap<>(); - - private final Map<ArtifactCoordsTuple, ModifiableExtensionRelease> releases = new LinkedHashMap<>(); - - private final ImmutableRegistry.Builder registryBuilder = Registry.builder(); - - @Override - public void visitPlatform(QuarkusPlatformDescriptor platform) { - registryBuilder.putCoreVersions(new ComparableVersion(platform.getQuarkusVersion()), new HashMap<>()); - registryBuilder.addAllCategories(platform.getCategories()); - - ArtifactKey platformKey = ImmutableArtifactKey.of(platform.getBomGroupId(), platform.getBomArtifactId()); - ModifiablePlatform platformBuilder = platforms.computeIfAbsent(platformKey, - key -> ModifiablePlatform.create().setId(key)); - - platformBuilder.addReleases(Release.builder().version(platform.getBomVersion()) - .quarkusCore(platform.getQuarkusVersion()) - .build()); - - ArtifactCoords platformCoords = ImmutableArtifactCoords.of(platformKey, platform.getBomVersion()); - for (Extension extension : platform.getExtensions()) { - visitExtension(extension, platform.getQuarkusVersion(), platformCoords); - } - } - - @Override - public void visitExtension(Extension extension, String quarkusCore) { - visitExtension(extension, quarkusCore, null); - } - - private void visitExtension(Extension extension, String quarkusCore, ArtifactCoords platform) { - // Ignore unlisted extensions - if (extension.isUnlisted()) { - return; - } - ArtifactKey extensionKey = ImmutableArtifactKey.of(extension.getGroupId(), extension.getArtifactId()); - ModifiableExtension extensionBuilder = extensions - .computeIfAbsent(extensionKey, key -> ModifiableExtension.create() - .setId(extensionKey) - .setName(Objects.toString(extension.getName(), extension.getArtifactId())) - .setDescription(extension.getDescription()) - .setMetadata(extension.getMetadata())); - ArtifactCoords coords = ImmutableArtifactCoords.of(extensionKey, extension.getVersion()); - ArtifactCoordsTuple key = ImmutableArtifactCoordsTuple.builder().coords(coords) - .quarkusVersion(quarkusCore) - .build(); - ModifiableExtensionRelease releaseBuilder = releases.computeIfAbsent(key, - appArtifactCoords -> ModifiableExtensionRelease.create() - .setRelease(Release.builder() - .version(appArtifactCoords.getCoords().getVersion()) - .quarkusCore(appArtifactCoords.getQuarkusVersion()) - .build())); - if (platform != null) { - Map<String, Object> metadata = diff(extensionBuilder.getMetadata(), extension.getMetadata()); - ExtensionPlatformRelease platformRelease = ImmutableExtensionPlatformRelease - .builder().coords(platform).metadata(metadata).build(); - releaseBuilder.addPlatforms(platformRelease); - } - } - - public Registry build() { - for (Map.Entry<ArtifactCoordsTuple, ModifiableExtensionRelease> entry : releases.entrySet()) { - ArtifactCoordsTuple tuple = entry.getKey(); - ModifiableExtensionRelease extensionReleaseBuilder = entry.getValue(); - ArtifactKey key = tuple.getCoords().getId(); - ModifiableExtension extensionBuilder = extensions.get(key); - extensionBuilder.addReleases(extensionReleaseBuilder.toImmutable()); - } - extensions.values().stream().map(ModifiableExtension::toImmutable).forEach(registryBuilder::addExtensions); - platforms.values().stream().map(ModifiablePlatform::toImmutable).forEach(registryBuilder::addPlatforms); - return registryBuilder.build(); - } - - static Map<String, Object> diff(Map<String, Object> left, Map<String, Object> right) { - Map<String, Object> result = new HashMap<>(); - for (Map.Entry<String, Object> entry : right.entrySet()) { - Object value = left.get(entry.getKey()); - if (!entry.getValue().equals(value)) { - result.put(entry.getKey(), entry.getValue()); - } - } - return result; - } - - @Value.Immutable - public interface ArtifactCoordsTuple { - @Value.Parameter - ArtifactCoords getCoords(); - - @Value.Parameter - String getQuarkusVersion(); - } - -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/builder/URLRegistryBuilder.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/builder/URLRegistryBuilder.java deleted file mode 100644 index 493c08e9afabd0..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/builder/URLRegistryBuilder.java +++ /dev/null @@ -1,51 +0,0 @@ -package io.quarkus.registry.builder; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.PropertyNamingStrategies; -import io.quarkus.registry.model.ImmutableRegistry; -import io.quarkus.registry.model.Registry; -import java.io.IOException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -public class URLRegistryBuilder { - - private final List<URL> urls = new ArrayList<>(); - - public URLRegistryBuilder addURL(URL url) { - urls.add(url); - return this; - } - - public URLRegistryBuilder addURLs(Collection<URL> urls) { - this.urls.addAll(urls); - return this; - } - - public Registry build() throws IOException { - if (urls.isEmpty()) { - throw new IllegalStateException("At least one URL must be specified"); - } - ObjectMapper mapper = new ObjectMapper() - .setSerializationInclusion(JsonInclude.Include.NON_NULL) - .setPropertyNamingStrategy(PropertyNamingStrategies.KEBAB_CASE); - if (urls.size() == 1) { - // Just one - return mapper.readValue(urls.get(0), Registry.class); - } else { - ImmutableRegistry.Builder builder = Registry.builder(); - for (URL url : urls) { - Registry aRegistry = mapper.readValue(url, Registry.class); - builder.addAllCategories(aRegistry.getCategories()) - .addAllExtensions(aRegistry.getExtensions()) - .addAllPlatforms(aRegistry.getPlatforms()) - .putAllCoreVersions(aRegistry.getCoreVersions()); - } - return builder.build(); - } - - } -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/catalog/model/Extension.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/catalog/model/Extension.java deleted file mode 100644 index bf7c365c59bd4e..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/catalog/model/Extension.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.quarkus.registry.catalog.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import io.quarkus.registry.model.Release; -import java.util.List; -import org.immutables.value.Value; - -/** - * An extension is a Maven dependency that can be added to a Quarkus project - */ -@Value.Immutable -@JsonDeserialize(as = ImmutableExtension.class) -public interface Extension { - - @JsonProperty("group-id") - String getGroupId(); - - @JsonProperty("artifact-id") - String getArtifactId(); - - @Value.Auxiliary - List<Release> getReleases(); - - static ImmutableExtension.Builder builder() { - return ImmutableExtension.builder(); - } -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/catalog/model/Platform.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/catalog/model/Platform.java deleted file mode 100644 index fd6e96a2542229..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/catalog/model/Platform.java +++ /dev/null @@ -1,42 +0,0 @@ -package io.quarkus.registry.catalog.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import io.quarkus.registry.model.Release; -import java.util.List; -import org.immutables.value.Value; - -/** - * A {@link Platform} holds a set of extensions - */ -@Value.Immutable -@JsonDeserialize(as = ImmutablePlatform.class) -public interface Platform { - - @JsonProperty("group-id") - String getGroupId(); - - @Value.Default - @JsonProperty("group-id-json") - @Value.Auxiliary - default String getGroupIdJson() { - return getGroupId(); - } - - @JsonProperty("artifact-id") - String getArtifactId(); - - @Value.Default - @JsonProperty("artifact-id-json") - @Value.Auxiliary - default String getArtifactIdJson() { - return getArtifactId(); - } - - @Value.Auxiliary - List<Release> getReleases(); - - static ImmutablePlatform.Builder builder() { - return ImmutablePlatform.builder(); - } -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/catalog/model/Repository.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/catalog/model/Repository.java deleted file mode 100644 index e51884b657529e..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/catalog/model/Repository.java +++ /dev/null @@ -1,60 +0,0 @@ -package io.quarkus.registry.catalog.model; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectReader; -import com.fasterxml.jackson.databind.PropertyNamingStrategies; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.type.CollectionType; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import org.immutables.value.Value.Immutable; - -@Immutable -@JsonDeserialize(as = ImmutableRepository.class) -public abstract class Repository { - - public abstract List<Extension> getIndividualExtensions(); - - public abstract List<Platform> getPlatforms(); - - /** - * - Match all files ending with '.json' inside an extensions directory - * - Match platforms.json - */ - public static Repository parse(Path rootPath, ObjectMapper mapper) { - ObjectReader reader = mapper.reader() - .with(mapper.getDeserializationConfig().with(PropertyNamingStrategies.KEBAB_CASE)); - return ImmutableRepository.builder() - .addAllPlatforms(parse(rootPath.resolve("platforms.json"), Platform.class, reader)) - .addAllIndividualExtensions(parse(rootPath.resolve("extensions"), Extension.class, reader)) - .build(); - } - - private static <T> Set<T> parse(Path root, Class<? extends T> type, ObjectReader reader) { - final Set<T> result = new HashSet<>(); - if (Files.isDirectory(root)) { - try (DirectoryStream<Path> stream = Files.newDirectoryStream(root, "*.json")) { - for (Path path : stream) { - result.add(reader.forType(type).readValue(path.toFile())); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } else { - CollectionType collectionType = reader.getTypeFactory().constructCollectionType(List.class, type); - try { - result.addAll(reader.forType(collectionType).readValue(root.toFile())); - } catch (IOException e) { - e.printStackTrace(); - } - } - return result; - } - -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/catalog/spi/ArtifactResolver.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/catalog/spi/ArtifactResolver.java deleted file mode 100644 index a2ed5907785674..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/catalog/spi/ArtifactResolver.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.quarkus.registry.catalog.spi; - -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.registry.catalog.model.Extension; -import io.quarkus.registry.catalog.model.Platform; -import io.quarkus.registry.model.Release; -import java.io.IOException; - -/** - * Resolves artifacts from the underlying artifact repositories - */ -public interface ArtifactResolver { - /** - * Resolve this specific platform - */ - QuarkusPlatformDescriptor resolvePlatform(Platform platform, Release release) throws IOException; - - /** - * Resolve this specific extension - */ - io.quarkus.dependencies.Extension resolveExtension(Extension extension, Release release) throws IOException; -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/catalog/spi/IndexVisitor.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/catalog/spi/IndexVisitor.java deleted file mode 100644 index d2e9c5f32af5f0..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/catalog/spi/IndexVisitor.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.quarkus.registry.catalog.spi; - -import io.quarkus.dependencies.Extension; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; - -public interface IndexVisitor { - - void visitPlatform(QuarkusPlatformDescriptor platform); - - void visitExtension(Extension extension, String quarkusCore); -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/ArtifactCoords.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/ArtifactCoords.java deleted file mode 100644 index dcb211448ddae7..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/ArtifactCoords.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.quarkus.registry.model; - -import com.fasterxml.jackson.annotation.JsonUnwrapped; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import org.immutables.value.Value; - -@Value.Immutable -@JsonDeserialize(as = ImmutableArtifactCoords.class) -public interface ArtifactCoords { - @Value.Parameter - @JsonUnwrapped - ArtifactKey getId(); - - @Value.Parameter - String getVersion(); -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/ArtifactKey.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/ArtifactKey.java deleted file mode 100644 index c38c3ef82b57a1..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/ArtifactKey.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.quarkus.registry.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import org.immutables.value.Value; - -@Value.Immutable -@JsonDeserialize(as = ImmutableArtifactKey.class) -public interface ArtifactKey { - @Value.Parameter - @JsonProperty("group-id") - String getGroupId(); - - @Value.Parameter - @JsonProperty("artifact-id") - String getArtifactId(); -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/Extension.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/Extension.java deleted file mode 100644 index 6e20e935ea8db4..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/Extension.java +++ /dev/null @@ -1,58 +0,0 @@ -package io.quarkus.registry.model; - -import com.fasterxml.jackson.annotation.JsonUnwrapped; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import java.util.Map; -import java.util.Set; -import java.util.SortedSet; -import org.immutables.value.Value; - -@Value.Immutable -@Value.Modifiable -@JsonDeserialize(as = ImmutableExtension.class) -public interface Extension { - - @JsonUnwrapped - ArtifactKey getId(); - - @Value.Auxiliary - String getName(); - - @Value.Auxiliary - @Nullable - String getDescription(); - - @Value.Auxiliary - Map<String, Object> getMetadata(); - - @Value.Auxiliary - @Value.ReverseOrder - SortedSet<ExtensionRelease> getReleases(); - - @Value.Immutable - @Value.Modifiable - @JsonDeserialize(as = ImmutableExtensionRelease.class) - interface ExtensionRelease extends Comparable<ExtensionRelease> { - - @JsonUnwrapped - Release getRelease(); - - @Value.Auxiliary - Set<ExtensionPlatformRelease> getPlatforms(); - - @Override - default int compareTo(ExtensionRelease o) { - return getRelease().compareTo(o.getRelease()); - } - } - - @Value.Immutable - @JsonDeserialize(as = ImmutableExtensionPlatformRelease.class) - interface ExtensionPlatformRelease { - @JsonUnwrapped - ArtifactCoords getCoords(); - - @Value.Auxiliary - Map<String, Object> getMetadata(); - } -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/Nullable.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/Nullable.java deleted file mode 100644 index 223b4cb0688419..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/Nullable.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.quarkus.registry.model; - -@interface Nullable { -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/Platform.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/Platform.java deleted file mode 100644 index 1c721254a74ee1..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/Platform.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.quarkus.registry.model; - -import com.fasterxml.jackson.annotation.JsonUnwrapped; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import java.util.Set; -import org.immutables.value.Value; - -@Value.Immutable -@Value.Modifiable -@JsonDeserialize(as = ImmutablePlatform.class) -public interface Platform { - - @JsonUnwrapped - ArtifactKey getId(); - - @Value.Auxiliary - Set<Release> getReleases(); -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/Registry.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/Registry.java deleted file mode 100644 index 7250c5af056920..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/Registry.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.quarkus.registry.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import io.quarkus.dependencies.Category; -import java.util.Map; -import java.util.Set; -import java.util.SortedMap; -import org.apache.maven.artifact.versioning.ComparableVersion; -import org.immutables.value.Value; - -@Value.Immutable -@JsonDeserialize(as = ImmutableRegistry.class) -public interface Registry { - - @JsonProperty("core-versions") - @Value.ReverseOrder - SortedMap<ComparableVersion, Map<String, String>> getCoreVersions(); - - Set<Extension> getExtensions(); - - Set<Platform> getPlatforms(); - - Set<Category> getCategories(); - - static ImmutableRegistry.Builder builder() { - return ImmutableRegistry.builder(); - } -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/Release.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/Release.java deleted file mode 100644 index 84e7650b56350f..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/model/Release.java +++ /dev/null @@ -1,37 +0,0 @@ -package io.quarkus.registry.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import org.apache.maven.artifact.versioning.ComparableVersion; -import org.immutables.value.Value; - -@Value.Immutable -@JsonDeserialize(as = ImmutableRelease.class) -public interface Release extends Comparable<Release> { - - String getVersion(); - - @Nullable - @JsonProperty("quarkus-core") - String getQuarkusCore(); - - @Nullable - @JsonProperty("repository-url") - @Value.Auxiliary - String getRepositoryURL(); - - static ImmutableRelease.Builder builder() { - return ImmutableRelease.builder(); - } - - @Override - default int compareTo(Release o) { - int compare = new ComparableVersion(getVersion()) - .compareTo(new ComparableVersion(o.getVersion())); - if (compare == 0 && (getQuarkusCore() != null && o.getQuarkusCore() != null)) { - compare = new ComparableVersion(getQuarkusCore()) - .compareTo(new ComparableVersion(o.getQuarkusCore())); - } - return compare; - } -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/package-info.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/package-info.java deleted file mode 100644 index 0c6504e3ca885f..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/registry/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -@Style(jdkOnly = true, visibility = PUBLIC, allowedClasspathAnnotations = { Override.class }) -package io.quarkus.registry; - -import static org.immutables.value.Value.Style.ImplementationVisibility.PUBLIC; - -import org.immutables.value.Value.Style; \ No newline at end of file diff --git a/independent-projects/tools/devtools-common/src/main/resources/META-INF/services/io.quarkus.devtools.project.codegen.ProjectGenerator b/independent-projects/tools/devtools-common/src/main/resources/META-INF/services/io.quarkus.devtools.project.codegen.ProjectGenerator deleted file mode 100644 index 41ba05fc1a3e40..00000000000000 --- a/independent-projects/tools/devtools-common/src/main/resources/META-INF/services/io.quarkus.devtools.project.codegen.ProjectGenerator +++ /dev/null @@ -1 +0,0 @@ -io.quarkus.devtools.project.codegen.rest.BasicRestProjectGenerator diff --git a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/devtools/project/buildfile/MavenBuildFileTest.java b/independent-projects/tools/devtools-common/src/test/java/io/quarkus/devtools/project/buildfile/MavenBuildFileTest.java index 88f10e174789bf..e0104ed2fe59d1 100644 --- a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/devtools/project/buildfile/MavenBuildFileTest.java +++ b/independent-projects/tools/devtools-common/src/test/java/io/quarkus/devtools/project/buildfile/MavenBuildFileTest.java @@ -4,7 +4,7 @@ import io.quarkus.bootstrap.model.AppArtifactCoords; import io.quarkus.maven.utilities.MojoUtils; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.registry.catalog.ExtensionCatalog; import java.io.IOException; import java.nio.file.Path; import java.util.Properties; @@ -39,7 +39,7 @@ void setUp(@TempDir Path projectDirPath) throws IOException { model.setDependencyManagement(depMan); Path pomPath = projectDirPath.resolve("pom.xml"); MojoUtils.write(model, pomPath.toFile()); - QuarkusPlatformDescriptor mock = Mockito.mock(QuarkusPlatformDescriptor.class); + ExtensionCatalog mock = Mockito.mock(ExtensionCatalog.class); mavenBuildFile = new MavenBuildFile(projectDirPath, mock); } diff --git a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/DefaultExtensionRegistryTest.java b/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/DefaultExtensionRegistryTest.java deleted file mode 100644 index fcf1fa3b1f480d..00000000000000 --- a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/DefaultExtensionRegistryTest.java +++ /dev/null @@ -1,82 +0,0 @@ -package io.quarkus.registry; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.PropertyNamingStrategies; -import io.quarkus.bootstrap.model.AppArtifactCoords; -import io.quarkus.devtools.project.extensions.ExtensionInstallPlan; -import io.quarkus.registry.builder.RegistryBuilder; -import io.quarkus.registry.catalog.model.Repository; -import io.quarkus.registry.model.Registry; -import java.io.File; -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Collections; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -class DefaultExtensionRegistryTest { - - static final ObjectMapper OBJECT_MAPPER = new ObjectMapper() - .setPropertyNamingStrategy(PropertyNamingStrategies.KEBAB_CASE) - .setSerializationInclusion(JsonInclude.Include.NON_NULL); - static DefaultExtensionRegistry extensionRegistry; - - @BeforeAll - static void setUp() throws IOException { - Repository repository = Repository.parse(Paths.get("src/test/resources/registry/repository"), OBJECT_MAPPER); - RegistryBuilder registryBuilder = new RegistryBuilder(); - RepositoryIndexer indexer = new RepositoryIndexer(new TestArtifactResolver()); - indexer.index(repository, registryBuilder); - Registry registry = registryBuilder.build(); - extensionRegistry = new DefaultExtensionRegistry(registry); - } - - @Test - void serializationShouldKeepValues(@TempDir Path tmpDir) throws IOException { - File tmpFile = tmpDir.resolve("registry.json").toFile(); - OBJECT_MAPPER.writeValue(tmpFile, extensionRegistry.getRegistry()); - Registry newRegistry = OBJECT_MAPPER.readValue(tmpFile, Registry.class); - assertThat(newRegistry).isEqualToComparingFieldByField(extensionRegistry.getRegistry()); - } - - @Test - void shouldReturnFourQuarkusCoreVersions() { - assertThat(extensionRegistry.getQuarkusCoreVersions()).containsExactly( - "1.6.0.Final", - "1.5.2.Final", - "1.3.2.Final"); - } - - @Test - void shouldLookupPlatformForDependentExtensionInQuarkusFinal() { - ExtensionInstallPlan result = extensionRegistry.planInstallation("1.3.2.Final", - Arrays.asList("quarkus-arc", "quarkus-vertx")); - assertThat(result).isNotNull(); - assertThat(result.getPlatforms()).hasSize(2); - assertThat(result.getPlatforms()) - .extracting(AppArtifactCoords::getArtifactId) - .contains("quarkus-universe-bom", "quarkus-bom"); - assertThat(result.getManagedExtensions()).hasSize(2); - assertThat(result.getIndependentExtensions()).isEmpty(); - } - - @Test - void shouldLookupNoPlatformForIndependentExtension() { - ExtensionInstallPlan result = extensionRegistry.planInstallation("1.3.1.Final", - Collections.singletonList("myfaces-quarkus-runtime")); - assertThat(result).isNotNull(); - assertThat(result.getPlatforms()).isEmpty(); - assertThat(result.getManagedExtensions()).isEmpty(); - assertThat(result.getIndependentExtensions()).hasSize(1); - assertThat(result.getIndependentExtensions().iterator().next()) - .hasFieldOrPropertyWithValue("groupId", "org.apache.myfaces.core.extensions.quarkus") - .hasFieldOrPropertyWithValue("artifactId", "myfaces-quarkus-runtime") - .hasFieldOrPropertyWithValue("version", "2.3-next-M2"); - } -} diff --git a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/RepositoryIndexerTest.java b/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/RepositoryIndexerTest.java deleted file mode 100644 index 282e311b0d7e38..00000000000000 --- a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/RepositoryIndexerTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.quarkus.registry; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.atLeast; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import com.fasterxml.jackson.databind.ObjectMapper; -import io.quarkus.dependencies.Extension; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.registry.catalog.model.Repository; -import io.quarkus.registry.catalog.spi.IndexVisitor; -import java.nio.file.Path; -import java.nio.file.Paths; -import org.junit.jupiter.api.Test; - -class RepositoryIndexerTest { - @Test - void shouldVisitParsedElements() throws Exception { - Path rootPath = Paths.get("src/test/resources/registry/repository"); - assertThat(rootPath).exists(); - ObjectMapper mapper = new ObjectMapper(); - Repository repository = Repository.parse(rootPath, mapper); - RepositoryIndexer indexer = new RepositoryIndexer(new TestArtifactResolver()); - IndexVisitor mock = mock(IndexVisitor.class); - indexer.index(repository, mock); - verify(mock, atLeast(4)).visitPlatform(any(QuarkusPlatformDescriptor.class)); - verify(mock, atLeast(2)).visitExtension(any(Extension.class), anyString()); - } -} diff --git a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/TestArtifactResolver.java b/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/TestArtifactResolver.java deleted file mode 100644 index 9e2581f99eb645..00000000000000 --- a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/TestArtifactResolver.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.quarkus.registry; - -import io.quarkus.dependencies.Extension; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.registry.catalog.model.Platform; -import io.quarkus.registry.catalog.spi.ArtifactResolver; -import io.quarkus.registry.model.Release; -import io.quarkus.test.platform.descriptor.loader.QuarkusTestPlatformDescriptorLoader; -import java.io.IOException; - -public class TestArtifactResolver implements ArtifactResolver { - - @Override - public QuarkusPlatformDescriptor resolvePlatform(Platform platform, Release release) { - final QuarkusTestPlatformDescriptorLoader loader = new QuarkusTestPlatformDescriptorLoader(); - loader.setGroupId(platform.getGroupId()); - loader.setArtifactId(platform.getArtifactId()); - loader.setVersion(release.getVersion()); - return loader.load(null); - } - - @Override - public Extension resolveExtension(io.quarkus.registry.catalog.model.Extension extension, Release release) - throws IOException { - return new Extension(extension.getGroupId(), extension.getArtifactId(), release.getVersion()); - } -} diff --git a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/builder/ExtensionRegistryBuilderTest.java b/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/builder/ExtensionRegistryBuilderTest.java deleted file mode 100644 index 7f6ead47774a9c..00000000000000 --- a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/builder/ExtensionRegistryBuilderTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.quarkus.registry.builder; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.atMostOnce; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.quarkus.registry.ExtensionRegistry; -import io.quarkus.registry.catalog.model.Extension; -import io.quarkus.registry.catalog.spi.ArtifactResolver; -import io.quarkus.registry.model.Release; -import java.io.IOException; -import org.junit.jupiter.api.Test; - -class ExtensionRegistryBuilderTest { - - @Test - void shouldResolveCamelDependencies() throws IOException { - String groupId = "org.apache.camel"; - String artifactId = "camel-quarkus"; - String version = "1.6.0.Final"; - - ArtifactResolver artifactResolver = mock(ArtifactResolver.class); - Release release = Release.builder().version(version).build(); - Extension extension = Extension.builder().groupId(groupId).artifactId(artifactId) - .addReleases(release).build(); - when(artifactResolver.resolveExtension(extension, release)) - .thenReturn(new io.quarkus.dependencies.Extension(groupId, artifactId, version)); - - ExtensionRegistry registry = new ExtensionRegistryBuilder(artifactResolver) - .addExtension(groupId, artifactId, version, version) - .build(); - verify(artifactResolver, atMostOnce()).resolveExtension(extension, release); - assertThat(registry.list(version, "camel")).isNotEmpty(); - } - -} diff --git a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/builder/RegistryBuilderTest.java b/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/builder/RegistryBuilderTest.java deleted file mode 100644 index a6a69ed15bd1c0..00000000000000 --- a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/builder/RegistryBuilderTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package io.quarkus.registry.builder; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.entry; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.PropertyNamingStrategies; -import io.quarkus.registry.RepositoryIndexer; -import io.quarkus.registry.TestArtifactResolver; -import io.quarkus.registry.catalog.model.Repository; -import io.quarkus.registry.model.Registry; -import java.io.IOException; -import java.nio.file.Paths; -import java.util.HashMap; -import java.util.Map; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -class RegistryBuilderTest { - - static Registry registry; - - @BeforeAll - static void setUp() throws IOException { - ObjectMapper mapper = new ObjectMapper(); - Repository repository = Repository.parse(Paths.get("src/test/resources/registry/repository"), mapper); - RepositoryIndexer indexer = new RepositoryIndexer(new TestArtifactResolver()); - RegistryBuilder builder = new RegistryBuilder(); - indexer.index(repository, builder); - registry = builder.build(); - } - - @Test - void build() throws Exception { - assertThat(registry.getExtensions()).isNotEmpty(); - assertThat(registry.getPlatforms()).isNotEmpty(); - if (Boolean.getBoolean("generateTmpRegistry")) { - ObjectMapper mapper = new ObjectMapper() - .setSerializationInclusion(JsonInclude.Include.NON_NULL) - .setPropertyNamingStrategy(PropertyNamingStrategies.KEBAB_CASE); - mapper.writeValue(new java.io.File("/tmp/registry.json"), registry); - } - } - - @Test - void diffMap() { - Map<String, Object> left = new HashMap<>(); - left.put("A", "1"); - left.put("B", "2"); - Map<String, Object> right = new HashMap<>(); - right.put("A", "1"); - right.put("B", "2"); - right.put("C", "3"); - Map<String, Object> result = RegistryBuilder.diff(left, right); - assertThat(result).doesNotContainKeys("A", "B").containsOnly(entry("C", "3")); - } - -} diff --git a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/builder/URLRegistryBuilderTest.java b/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/builder/URLRegistryBuilderTest.java deleted file mode 100644 index 5cad5d6368c3a9..00000000000000 --- a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/builder/URLRegistryBuilderTest.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.quarkus.registry.builder; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import io.quarkus.registry.model.Registry; -import java.io.IOException; -import java.net.URL; -import org.junit.jupiter.api.Test; - -class URLRegistryBuilderTest { - - @Test - void shouldFailOnEmptyURLS() { - assertThrows(IllegalStateException.class, new URLRegistryBuilder()::build); - } - - @Test - void shouldReadRegistry() throws IOException { - URL url = getClass().getClassLoader().getResource("registry/registry.json"); - Registry registry = new URLRegistryBuilder().addURL(url).build(); - assertThat(registry.getCoreVersions()).isNotEmpty(); - } -} diff --git a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/model/RepositoryTest.java b/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/model/RepositoryTest.java deleted file mode 100644 index 35cd832fa3945f..00000000000000 --- a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/registry/model/RepositoryTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.quarkus.registry.model; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.fasterxml.jackson.databind.ObjectMapper; -import io.quarkus.registry.catalog.model.Repository; -import java.nio.file.Paths; -import org.junit.jupiter.api.Test; - -class RepositoryTest { - - @Test - void shouldParseRepository() throws Exception { - Repository repository = Repository.parse(Paths.get("src/test/resources/registry/repository"), new ObjectMapper()); - assertThat(repository).isNotNull(); - assertThat(repository.getPlatforms()).isNotEmpty(); - assertThat(repository.getIndividualExtensions()).isNotEmpty(); - } -} diff --git a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/test/platform/descriptor/CombinedQuarkusPlatformDescriptorTest.java b/independent-projects/tools/devtools-common/src/test/java/io/quarkus/test/platform/descriptor/CombinedQuarkusPlatformDescriptorTest.java deleted file mode 100644 index f7f72424e5b174..00000000000000 --- a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/test/platform/descriptor/CombinedQuarkusPlatformDescriptorTest.java +++ /dev/null @@ -1,95 +0,0 @@ -package io.quarkus.test.platform.descriptor; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import io.quarkus.dependencies.Category; -import io.quarkus.dependencies.Extension; -import io.quarkus.platform.descriptor.CombinedQuarkusPlatformDescriptor; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class CombinedQuarkusPlatformDescriptorTest extends PlatformAwareTestBase { - - private static final String DOMINATING_VERSION = "dominating-version"; - - QuarkusPlatformDescriptor dominatingPlatform; - QuarkusPlatformDescriptor defaultPlatform; - - @BeforeEach - public void setup() { - dominatingPlatform = new TestDominatingQuarkusPlatformDescriptor(); - defaultPlatform = getPlatformDescriptor(); - } - - @Test - public void testDominance() throws Exception { - - final QuarkusPlatformDescriptor combined = CombinedQuarkusPlatformDescriptor.builder() - .addPlatform(dominatingPlatform) - .addPlatform(defaultPlatform) - .build(); - - final Map<String, Extension> expectedExtensions = toMap(defaultPlatform.getExtensions()); - expectedExtensions.putAll(toMap(dominatingPlatform.getExtensions())); - - assertBom(combined); - - assertEquals(dominatingPlatform.getQuarkusVersion(), combined.getQuarkusVersion()); - - assertCategories(combined); - - assertExtensions(expectedExtensions, combined); - - assertEquals("dominating pom.xml template", combined.getTemplate("dir/some-other-file.template")); - assertEquals(defaultPlatform.getTemplate("dir/some-file.template"), - combined.getTemplate("dir/some-file.template")); - } - - private void assertBom(QuarkusPlatformDescriptor descriptor) { - assertEquals(dominatingPlatform.getBomGroupId(), descriptor.getBomGroupId()); - assertEquals(dominatingPlatform.getBomArtifactId(), descriptor.getBomArtifactId()); - assertEquals(dominatingPlatform.getBomVersion(), descriptor.getBomVersion()); - } - - private void assertCategories(QuarkusPlatformDescriptor descriptor) { - final List<Category> categories = descriptor.getCategories(); - assertFalse(categories.isEmpty()); - final Map<String, Category> map = categories.stream().collect(Collectors.toMap(Category::getId, c -> c)); - assertEquals("Dominating Web", map.get("web").getName()); - assertEquals("Data", map.get("data").getName()); - assertEquals("Other category", map.get("other").getName()); - } - - private void assertExtensions(Map<String, Extension> expectedExtensions, QuarkusPlatformDescriptor descriptor) { - final List<Extension> extensions = descriptor.getExtensions(); - assertFalse(extensions.isEmpty()); - for (Extension actual : extensions) { - final Extension expected = expectedExtensions.get(getGa(actual)); - assertNotNull(expected); - assertEquals(expected.getVersion(), actual.getVersion()); - } - - final Map<String, Extension> actualMap = toMap(descriptor.getExtensions()); - Extension ext = actualMap.get("io.quarkus:quarkus-jdbc-h2"); - assertNotNull(ext); - assertEquals(defaultPlatform.getQuarkusVersion(), ext.getVersion()); - - ext = actualMap.get("io.quarkus:quarkus-resteasy"); - assertNotNull(ext); - assertEquals(DOMINATING_VERSION, ext.getVersion()); - } - - private static Map<String, Extension> toMap(final List<Extension> extensions) { - return extensions.stream().collect(Collectors.toMap(e -> getGa(e), e -> e)); - } - - private static String getGa(Extension e) { - return e.getGroupId() + ":" + e.getArtifactId(); - } -} diff --git a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/test/platform/descriptor/PlatformAwareTestBase.java b/independent-projects/tools/devtools-common/src/test/java/io/quarkus/test/platform/descriptor/PlatformAwareTestBase.java deleted file mode 100644 index 0cf687fef93049..00000000000000 --- a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/test/platform/descriptor/PlatformAwareTestBase.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.quarkus.test.platform.descriptor; - -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.tools.config.QuarkusPlatformConfig; - -public class PlatformAwareTestBase { - - private QuarkusPlatformDescriptor platformDescr; - - protected QuarkusPlatformDescriptor getPlatformDescriptor() { - return platformDescr == null ? platformDescr = QuarkusPlatformConfig.builder().build().getPlatformDescriptor() - : platformDescr; - } - - protected String getBomGroupId() { - return getPlatformDescriptor().getBomGroupId(); - } - - protected String getBomArtifactId() { - return getPlatformDescriptor().getBomArtifactId(); - } - - protected String getBomVersion() { - return getPlatformDescriptor().getBomVersion(); - } -} diff --git a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/test/platform/descriptor/TestDominatingQuarkusPlatformDescriptor.java b/independent-projects/tools/devtools-common/src/test/java/io/quarkus/test/platform/descriptor/TestDominatingQuarkusPlatformDescriptor.java deleted file mode 100644 index b8e77157072b38..00000000000000 --- a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/test/platform/descriptor/TestDominatingQuarkusPlatformDescriptor.java +++ /dev/null @@ -1,77 +0,0 @@ -package io.quarkus.test.platform.descriptor; - -import static io.quarkus.test.platform.descriptor.loader.QuarkusTestPlatformDescriptorLoader.addCategory; -import static io.quarkus.test.platform.descriptor.loader.QuarkusTestPlatformDescriptorLoader.addExtension; - -import io.quarkus.bootstrap.model.AppArtifactCoords; -import io.quarkus.dependencies.Category; -import io.quarkus.dependencies.Extension; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.descriptor.ResourceInputStreamConsumer; -import io.quarkus.platform.descriptor.ResourcePathConsumer; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -public class TestDominatingQuarkusPlatformDescriptor implements QuarkusPlatformDescriptor { - - private final List<Category> categories = new ArrayList<>(); - private final List<Extension> extensions = new ArrayList<>(); - - public TestDominatingQuarkusPlatformDescriptor() { - - addCategory("other", "Other category", categories); - addCategory("web", "Dominating Web", categories); - - addExtension(new AppArtifactCoords("io.quarkus", "quarkus-resteasy", "dominating-version"), "Dominating RESTEasy", - "dominating/guide", "reasteasy", extensions); - } - - @Override - public String getBomGroupId() { - return "dominating.bom.group.id"; - } - - @Override - public String getBomArtifactId() { - return "dominating.bom.artifact.id"; - } - - @Override - public String getBomVersion() { - return "dominating.bom.version"; - } - - @Override - public String getQuarkusVersion() { - return "dominating.quarkus.version"; - } - - @Override - public List<Extension> getExtensions() { - return extensions; - } - - @Override - public List<Category> getCategories() { - return categories; - } - - @Override - public String getTemplate(String name) { - if ("dir/some-other-file.template".equals(name)) { - return "dominating pom.xml template"; - } - return null; - } - - @Override - public <T> T loadResource(String name, ResourceInputStreamConsumer<T> consumer) throws IOException { - return null; - } - - @Override - public <T> T loadResourceAsPath(String name, ResourcePathConsumer<T> consumer) throws IOException { - return null; - } -} diff --git a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/test/platform/descriptor/loader/QuarkusTestPlatformDescriptorLoader.java b/independent-projects/tools/devtools-common/src/test/java/io/quarkus/test/platform/descriptor/loader/QuarkusTestPlatformDescriptorLoader.java deleted file mode 100644 index a3e4ca798e8203..00000000000000 --- a/independent-projects/tools/devtools-common/src/test/java/io/quarkus/test/platform/descriptor/loader/QuarkusTestPlatformDescriptorLoader.java +++ /dev/null @@ -1,235 +0,0 @@ -package io.quarkus.test.platform.descriptor.loader; - -import io.quarkus.bootstrap.model.AppArtifactCoords; -import io.quarkus.dependencies.Category; -import io.quarkus.dependencies.Extension; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.descriptor.ResourceInputStreamConsumer; -import io.quarkus.platform.descriptor.ResourcePathConsumer; -import io.quarkus.platform.descriptor.loader.QuarkusPlatformDescriptorLoader; -import io.quarkus.platform.descriptor.loader.QuarkusPlatformDescriptorLoaderContext; -import io.quarkus.platform.descriptor.loader.json.ResourceLoaders; -import io.quarkus.platform.tools.ToolsConstants; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.StringWriter; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Properties; - -public class QuarkusTestPlatformDescriptorLoader - implements QuarkusPlatformDescriptorLoader<QuarkusPlatformDescriptor, QuarkusPlatformDescriptorLoaderContext> { - - private static final List<Extension> extensions = new ArrayList<>(); - private static final Properties quarkusProps; - - private static final String quarkusVersion; - private static final List<Category> categories = new ArrayList<>(); - - private String groupId = "io.quarkus"; - private String artifactId = "quarkus-bom"; - private String version; - - private static void addCategories() { - addCategory("web", "Web"); - addCategory("data", "Data"); - addCategory("messaging", "Messaging"); - addCategory("core", "Core"); - addCategory("reactive", "Reactive"); - addCategory("cloud", "Cloud"); - } - - private static void addExtensions() { - addExtension("quarkus-agroal", "Agroal"); - addExtension("quarkus-arc", "Arc"); - addExtension("quarkus-kotlin", "Kotlin", "url://", "kotlin"); - addExtension("quarkus-scala", "Scala", "url://", "scala"); - addExtension("quarkus-config-yaml", "Config Yaml", "url://", "config-yaml"); - addExtension("quarkus-hibernate-orm-panache", "Hibernate ORM Panache"); - addExtension("quarkus-hibernate-search-orm-elasticsearch", "Elasticsearch"); - addExtension("quarkus-hibernate-validator", "Hibernate Validator"); - addExtension("quarkus-jdbc-postgresql", "JDBC PostreSQL"); - addExtension("quarkus-jdbc-h2", "JDBC H2"); - addExtension("quarkus-resteasy", "RESTEasy", "https://quarkus.io/guides/rest-json", "resteasy"); - - addExtension("quarkus-smallrye-reactive-messaging", "SmallRye Reactive Messaging"); - addExtension("quarkus-smallrye-reactive-streams-operators", "SmallRye Reactive Streams Operators"); - addExtension("quarkus-smallrye-opentracing", "SmallRye Opentracing"); - addExtension("quarkus-smallrye-metrics", "SmallRye Metrics"); - addExtension("quarkus-smallrye-reactive-messaging-kafka", "SmallRye Reactive Messaging Kafka"); - addExtension("quarkus-smallrye-health", "SmallRye Health"); - addExtension("quarkus-smallrye-openapi", "SmallRye Open API"); - addExtension("quarkus-smallrye-jwt", "SmallRye JWT"); - addExtension("quarkus-smallrye-context-propagation", "SmallRye Context Propagation"); - addExtension("quarkus-smallrye-reactive-type-converters", "SmallRye Reactive Type Converters"); - addExtension("quarkus-smallrye-reactive-messaging-amqp", "SmallRye Reactive Messaging AMQP"); - addExtension("quarkus-smallrye-fault-tolerance", "SmallRye Fault Tolerance"); - - addExtension("quarkus-vertx", "Vert.X"); - } - - private static void addExtension(String artifactId, String name) { - addExtension(artifactId, name, "url://" + name); - } - - private static void addExtension(String artifactId, String name, String guide) { - addExtension(artifactId, name, guide, null); - } - - private static void addExtension(String artifactId, String name, String guide, String codestart) { - addExtension(new AppArtifactCoords("io.quarkus", artifactId, quarkusVersion), name, guide, codestart); - } - - private static void addExtension(AppArtifactCoords coords, String name, String guide, String codestart) { - addExtension(coords, name, guide, codestart, extensions); - } - - public static void addExtension(AppArtifactCoords coords, String name, String guide, String codestart, - List<Extension> extensions) { - final Extension e = new Extension(coords.getGroupId(), coords.getArtifactId(), coords.getVersion()) - .setName(name) - .setGuide(guide); - if (codestart != null) { - e.setCodestart(codestart); - } - extensions.add(e); - } - - private static void addCategory(String id, String name) { - addCategory(id, name, categories); - } - - public static void addCategory(String id, String name, List<Category> categories) { - Category cat = new Category(); - cat.setId(id); - cat.setName(name); - categories.add(cat); - } - - public void setGroupId(String groupId) { - this.groupId = groupId; - } - - public void setArtifactId(String artifactId) { - this.artifactId = artifactId; - } - - public void setVersion(String version) { - this.version = version; - } - - static { - try { - quarkusProps = loadStaticResource("quarkus.properties", is -> { - final Properties props = new Properties(); - props.load(is); - return props; - }); - } catch (IOException e) { - throw new IllegalStateException("Failed to load quarkus.properties", e); - } - quarkusVersion = quarkusProps.getProperty(ToolsConstants.PROP_QUARKUS_CORE_VERSION); - if (quarkusVersion == null) { - throw new IllegalStateException( - ToolsConstants.PROP_QUARKUS_CORE_VERSION + " property is missing from quarkus.properties"); - } - - addCategories(); - addExtensions(); - } - - @Override - public QuarkusPlatformDescriptor load(QuarkusPlatformDescriptorLoaderContext context) { - return new QuarkusPlatformDescriptor() { - - @Override - public String getBomGroupId() { - return groupId; - } - - @Override - public String getBomArtifactId() { - return artifactId; - } - - @Override - public String getBomVersion() { - return Objects.toString(version, quarkusVersion); - } - - @Override - public String getQuarkusVersion() { - return Objects.toString(version, quarkusVersion); - } - - @Override - public List<Extension> getExtensions() { - return extensions; - } - - @Override - public String getTemplate(String name) { - try { - return loadResource(name, is -> { - final StringWriter writer = new StringWriter(); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); - BufferedWriter bw = new BufferedWriter(writer)) { - String line; - while ((line = reader.readLine()) != null) { - bw.write(line); - bw.newLine(); - } - } - return writer.getBuffer().toString(); - }); - } catch (IOException e) { - throw new IllegalStateException("Failed to load resource " + name, e); - } - } - - @Override - public <T> T loadResource(String name, ResourceInputStreamConsumer<T> consumer) throws IOException { - return loadStaticResource(name, consumer); - } - - @Override - public <T> T loadResourceAsPath(String name, ResourcePathConsumer<T> consumer) throws IOException { - return loadStaticResourcePath(name, consumer); - } - - @Override - public List<Category> getCategories() { - return categories; - } - }; - } - - private static <T> T loadStaticResource(String name, ResourceInputStreamConsumer<T> consumer) throws IOException { - final InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(name); - if (is == null) { - throw new IOException("Failed to locate resource " + name + " on the classpath"); - } - try { - return consumer.consume(is); - } finally { - is.close(); - } - } - - private static <T> T loadStaticResourcePath(String name, ResourcePathConsumer<T> consumer) throws IOException { - final URL url = Thread.currentThread().getContextClassLoader().getResource(name); - final File file = ResourceLoaders.getResourceFile(url, name); - if (!Files.exists(file.toPath())) { - throw new IOException("Failed to locate resource " + name + " on the classpath"); - } - return consumer.consume(file.toPath()); - } -} diff --git a/independent-projects/tools/devtools-common/src/test/resources/META-INF/services/io.quarkus.platform.descriptor.loader.QuarkusPlatformDescriptorLoader b/independent-projects/tools/devtools-common/src/test/resources/META-INF/services/io.quarkus.platform.descriptor.loader.QuarkusPlatformDescriptorLoader deleted file mode 100644 index d891464c6f8e9a..00000000000000 --- a/independent-projects/tools/devtools-common/src/test/resources/META-INF/services/io.quarkus.platform.descriptor.loader.QuarkusPlatformDescriptorLoader +++ /dev/null @@ -1 +0,0 @@ -io.quarkus.test.platform.descriptor.loader.QuarkusTestPlatformDescriptorLoader \ No newline at end of file diff --git a/independent-projects/tools/devtools-common/src/test/resources/registry/registry.json b/independent-projects/tools/devtools-common/src/test/resources/registry/registry.json deleted file mode 100644 index 0ce8d67c77a054..00000000000000 --- a/independent-projects/tools/devtools-common/src/test/resources/registry/registry.json +++ /dev/null @@ -1,202 +0,0 @@ -{ - "core-versions": { - "1.5.1.Final": {}, - "1.4.2.Final": {}, - "1.3.4.Final": {} - }, - "extensions" : [ - { - "group-id":"io.quarkus", - "artifact-id":"quarkus-resteasy", - "name":"RESTEasy JAX-RS", - "description":"REST endpoint framework implementing JAX-RS and more", - "metadata":{ - "short-name":"jax-rs", - "keywords":[ - "resteasy", - "jaxrs", - "web", - "rest" - ], - "guide":"https://quarkus.io/guides/rest-json", - "categories":[ - "web" - ], - "status":"stable" - }, - "releases":[ - { - "platforms":[ - { - "group-id":"io.quarkus", - "artifact-id":"quarkus-universe-bom", - "version":"1.5.1.Final" - }, - { - "group-id":"io.quarkus", - "artifact-id":"quarkus-bom", - "version":"1.5.1.Final" - } - ], - "version":"1.5.1.Final", - "quarkus-core":"1.5.1.Final" - }, - { - "platforms":[ - { - "group-id":"io.quarkus", - "artifact-id":"quarkus-universe-bom", - "version":"1.4.2.Final" - }, - { - "group-id":"io.quarkus", - "artifact-id":"quarkus-bom", - "version":"1.4.2.Final" - } - ], - "version":"1.4.2.Final", - "quarkus-core":"1.4.2.Final" - }, - { - "platforms":[ - { - "group-id":"io.quarkus", - "artifact-id":"quarkus-universe-bom", - "version":"1.3.4.Final" - }, - { - "group-id":"io.quarkus", - "artifact-id":"quarkus-bom", - "version":"1.3.4.Final" - } - ], - "version":"1.3.4.Final", - "quarkus-core":"1.3.4.Final" - } - ] - }, - { - "group-id":"io.quarkus", - "artifact-id":"quarkus-resteasy-jackson", - "name":"RESTEasy Jackson", - "description":"Jackson serialization support for RESTEasy", - "metadata":{ - "keywords":[ - "resteasy-jackson", - "jaxrs-json", - "resteasy-json", - "resteasy", - "jaxrs", - "json", - "jackson" - ], - "categories":[ - "web", - "serialization" - ], - "status":"stable" - }, - "releases":[ - { - "platforms":[ - { - "group-id":"io.quarkus", - "artifact-id":"quarkus-universe-bom", - "version":"1.5.1.Final" - }, - { - "group-id":"io.quarkus", - "artifact-id":"quarkus-bom", - "version":"1.5.1.Final" - } - ], - "version":"1.5.1.Final", - "quarkus-core":"1.5.1.Final" - }, - { - "platforms":[ - { - "group-id":"io.quarkus", - "artifact-id":"quarkus-universe-bom", - "version":"1.4.2.Final" - }, - { - "group-id":"io.quarkus", - "artifact-id":"quarkus-bom", - "version":"1.4.2.Final" - } - ], - "version":"1.4.2.Final", - "quarkus-core":"1.4.2.Final" - }, - { - "platforms":[ - { - "group-id":"io.quarkus", - "artifact-id":"quarkus-universe-bom", - "version":"1.3.4.Final" - }, - { - "group-id":"io.quarkus", - "artifact-id":"quarkus-bom", - "version":"1.3.4.Final" - } - ], - "version":"1.3.4.Final", - "quarkus-core":"1.3.4.Final" - } - ] - } - ], - "platforms":[ - { - "group-id":"io.quarkus", - "artifact-id":"quarkus-universe-bom", - "releases":[ - { - "version":"1.5.1.Final", - "quarkus-core":"1.5.1.Final" - }, - { - "version":"1.4.2.Final", - "quarkus-core":"1.4.2.Final" - }, - { - "version":"1.3.4.Final", - "quarkus-core":"1.3.4.Final" - } - ] - }, - { - "group-id":"io.quarkus", - "artifact-id":"quarkus-bom", - "releases":[ - { - "version":"1.5.1.Final", - "quarkus-core":"1.5.1.Final" - }, - { - "version":"1.4.2.Final", - "quarkus-core":"1.4.2.Final" - }, - { - "version":"1.3.4.Final", - "quarkus-core":"1.3.4.Final" - } - ] - } - ], - "categories":[ - { - "id":"web", - "name":"Web", - "description":"Everything you need for REST endpoints, HTTP and web formats like JSON", - "metadata":{ - "pinned":[ - "io.quarkus:quarkus-resteasy", - "io.quarkus:quarkus-resteasy-jackson" - ] - } - } - ] -} \ No newline at end of file diff --git a/independent-projects/tools/devtools-common/src/test/resources/registry/repository/extensions/jsf.json b/independent-projects/tools/devtools-common/src/test/resources/registry/repository/extensions/jsf.json deleted file mode 100644 index 7dedaad1cee999..00000000000000 --- a/independent-projects/tools/devtools-common/src/test/resources/registry/repository/extensions/jsf.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "group-id": "org.apache.myfaces.core.extensions.quarkus", - "artifact-id": "myfaces-quarkus-runtime", - "releases": [ - { - "version": "2.3-next-M2", - "quarkus-core": "1.3.1.Final" - }, - { - "version": "2.3-next-M1", - "quarkus-core": "1.1.0.CR1" - } - ] -} \ No newline at end of file diff --git a/independent-projects/tools/devtools-common/src/test/resources/registry/repository/platforms.json b/independent-projects/tools/devtools-common/src/test/resources/registry/repository/platforms.json deleted file mode 100644 index 7d16491842aa3c..00000000000000 --- a/independent-projects/tools/devtools-common/src/test/resources/registry/repository/platforms.json +++ /dev/null @@ -1,30 +0,0 @@ -[ - { - "group-id": "io.quarkus", - "artifact-id": "quarkus-universe-bom", - "releases": [ - { - "version": "1.5.2.Final" - }, - { - "version": "1.3.2.Final" - } - ] - }, - { - "group-id": "io.quarkus", - "artifact-id": "quarkus-bom", - "artifact-id-json": "quarkus-bom-descriptor-json", - "releases": [ - { - "version": "1.6.0.Final" - }, - { - "version": "1.5.2.Final" - }, - { - "version": "1.3.2.Final" - } - ] - } -] diff --git a/independent-projects/tools/message-writer/pom.xml b/independent-projects/tools/message-writer/pom.xml index 3ef13025f1d0d3..4d33f90355d1c8 100644 --- a/independent-projects/tools/message-writer/pom.xml +++ b/independent-projects/tools/message-writer/pom.xml @@ -19,5 +19,4 @@ <artifactId>quarkus-devtools-message-writer</artifactId> <name>Quarkus - Dev tools - Message Writer</name> - </project> \ No newline at end of file diff --git a/independent-projects/tools/platform-descriptor-api/pom.xml b/independent-projects/tools/platform-descriptor-api/pom.xml deleted file mode 100644 index 7d4d978905f95f..00000000000000 --- a/independent-projects/tools/platform-descriptor-api/pom.xml +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-tools-parent</artifactId> - <version>999-SNAPSHOT</version> - </parent> - - <artifactId>quarkus-platform-descriptor-api</artifactId> - <name>Quarkus - Dev tools - Platform Descriptor API</name> - - <dependencies> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-devtools-message-writer</artifactId> - </dependency> - <dependency> - <groupId>org.apache.maven</groupId> - <artifactId>maven-model</artifactId> - </dependency> - <dependency> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <scope>test</scope> - </dependency> - </dependencies> -</project> diff --git a/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/dependencies/Extension.java b/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/dependencies/Extension.java deleted file mode 100644 index f867b080c8561a..00000000000000 --- a/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/dependencies/Extension.java +++ /dev/null @@ -1,305 +0,0 @@ -package io.quarkus.dependencies; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import org.apache.maven.model.Dependency; - -/** - * @author <a href="http://escoffier.me">Clement Escoffier</a> - * @author <a href="http://kenfinnigan.me">Ken Finnigan</a> - */ -public class Extension implements Serializable { - - public static final String GROUP_ID = "group-id"; - - public static final String ARTIFACT_ID = "artifact-id"; - - public static final String VERSION = "version"; - - public static final String MD_SHORT_NAME = "short-name"; - - public static final String MD_CODESTART = "codestart"; - - public static final String MD_GUIDE = "guide"; - - /** Key used for keywords in metadata **/ - public static String MD_KEYWORDS = "keywords"; - - public static final String MD_UNLISTED = "unlisted"; - - public static final String MD_STATUS = "status"; - - private String artifactId; - private String groupId; - private String scope; - private String version; - - private String type; - private String classifier; - - private String name; - private String description; - - private String simplifiedArtifactId; - private static final transient Pattern QUARKUS_PREFIX = Pattern.compile("^quarkus-"); - - private Map<String, Object> metadata = new HashMap<String, Object>(3); - - public Extension() { - // Use by mapper. - } - - public Extension(String groupId, String artifactId, String version) { - this.groupId = groupId; - this.setArtifactId(artifactId); - this.version = version; - } - - public String getArtifactId() { - return artifactId; - } - - public Extension setArtifactId(String artifactId) { - this.artifactId = artifactId; - this.simplifiedArtifactId = QUARKUS_PREFIX.matcher(artifactId).replaceFirst(""); - return this; - } - - /** Group Id for the extension artifact */ - public String getGroupId() { - return groupId; - } - - public Extension setGroupId(String groupId) { - this.groupId = groupId; - return this; - } - - public String getScope() { - return scope; - } - - public Extension setScope(String scope) { - this.scope = scope; - return this; - } - - public String getVersion() { - return version; - } - - public Extension setVersion(String version) { - this.version = version; - return this; - } - - public String getType() { - return type; - } - - public Extension setType(String type) { - this.type = type; - return this; - } - - public String getClassifier() { - return classifier; - } - - public Extension setClassifier(String classifier) { - this.classifier = classifier; - return this; - } - - public String getName() { - return name; - } - - public Extension setName(String name) { - this.name = name; - return this; - } - - public String getDescription() { - return description; - } - - public Extension setDescription(String description) { - this.description = description; - return this; - } - - /** - * Semi-Unstructured metadata used to provide metadata to tools and other - * frontends. - * - */ - public Map<String, Object> getMetadata() { - return metadata; - } - - public Extension setMetadata(Map<String, Object> metadata) { - this.metadata = metadata; - return this; - } - - public List<String> getKeywords() { - List<String> kw = (List<String>) getMetadata().get(MD_KEYWORDS); - return kw == null ? Collections.emptyList() : kw; - } - - public Extension setKeywords(String[] keywords) { - getMetadata().put(MD_KEYWORDS, Arrays.asList(keywords)); - return this; - } - - /** - * List of strings to use for matching. - * - * Returns keywords + artifactid all in lowercase. - * - * @return list of labels to use for matching. - */ - public List<String> labelsForMatching() { - List<String> list = new ArrayList<>(); - List<String> keywords = getKeywords(); - if (keywords != null) { - list.addAll(keywords.stream().map(String::toLowerCase).collect(Collectors.toList())); - } - list.add(artifactId.toLowerCase()); - return list; - } - - /** - * Convert this Extension into a dependency - * - * @param stripVersion if provided version will not be set on the Dependency - * @return a Maven {@link Dependency} object - */ - public Dependency toDependency(boolean stripVersion) { - Dependency dependency = new Dependency(); - dependency.setGroupId(groupId); - dependency.setArtifactId(artifactId); - if (scope != null && !scope.isEmpty()) { - dependency.setScope(scope); - } - if (classifier != null && !classifier.isEmpty()) { - dependency.setClassifier(classifier); - } - if (version != null && !version.isEmpty() && !stripVersion) { - dependency.setVersion(version); - } - if (type != null && !type.isEmpty()) { - dependency.setType(type); - } - return dependency; - } - - public String managementKey() { - return getGroupId() + ":" + getArtifactId(); - } - - public String gav() { - return managementKey() + ":" + version; - } - - public String getSimplifiedArtifactId() { - return simplifiedArtifactId; - } - - @Override - public String toString() { - return gav(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Extension extension = (Extension) o; - return Objects.equals(artifactId, extension.artifactId) && - Objects.equals(groupId, extension.groupId) && - Objects.equals(version, extension.version); - } - - @Override - public int hashCode() { - return Objects.hash(artifactId, groupId, version); - } - - public Extension setGuide(String guide) { - getMetadata().put(MD_GUIDE, guide); - return this; - } - - /** - * - * @return string representing the location of primary guide for this extension. - */ - public String getGuide() { - return (String) getMetadata().get(MD_GUIDE); - } - - public String getShortName() { - String shortName = (String) getMetadata().get(MD_SHORT_NAME); - if (shortName == null) { - return name; - } else { - return shortName; - } - } - - public Extension setShortName(String shortName) { - getMetadata().put(MD_SHORT_NAME, shortName); - return this; - } - - public String getCodestart() { - return (String) getMetadata().get(MD_CODESTART); - } - - public Extension setCodestart(String codestart) { - getMetadata().put(MD_CODESTART, codestart); - return this; - } - - public boolean isUnlisted() { - Object val = getMetadata().get(MD_UNLISTED); - if (val == null) { - return false; - } else if (val instanceof Boolean) { - return (Boolean) val; - } else if (val instanceof String) { - return Boolean.parseBoolean((String) val); - } - - return false; - } - - public void setUnlisted(boolean unlisted) { - getMetadata().put(MD_UNLISTED, unlisted); - } - - public Extension addMetadata(String key, Object value) { - getMetadata().put(key, value); - return this; - - } - - public Extension removeMetadata(String key) { - getMetadata().remove(key); - return this; - } -} diff --git a/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/platform/descriptor/CombinedQuarkusPlatformDescriptor.java b/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/platform/descriptor/CombinedQuarkusPlatformDescriptor.java deleted file mode 100644 index 53d3f359f2271c..00000000000000 --- a/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/platform/descriptor/CombinedQuarkusPlatformDescriptor.java +++ /dev/null @@ -1,210 +0,0 @@ -package io.quarkus.platform.descriptor; - -import io.quarkus.dependencies.Category; -import io.quarkus.dependencies.Extension; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import org.apache.maven.model.Dependency; - -/** - * Platform descriptor that is composed of multiple platform descriptors. - * The order in which descriptors are added is significant. Platform descriptor - * added earlier dominate over those added later. - */ -public class CombinedQuarkusPlatformDescriptor implements QuarkusPlatformDescriptor { - - public static class Builder { - - private final List<QuarkusPlatformDescriptor> platforms = new ArrayList<>(); - - private Builder() { - } - - /** - * Adds a platform descriptor. - * The order in which descriptors are added is significant. Platform descriptor - * added earlier dominate over those added later. - * - * @param platform platform descriptor to add - * @return this builder instance - */ - public Builder addPlatform(QuarkusPlatformDescriptor platform) { - platforms.add(platform); - return this; - } - - public QuarkusPlatformDescriptor build() { - if (platforms.size() == 1) { - return platforms.get(0); - } - return new CombinedQuarkusPlatformDescriptor(this); - } - } - - public static Builder builder() { - return new Builder(); - } - - private final QuarkusPlatformDescriptor master; - private final List<QuarkusPlatformDescriptor> platforms; - private List<Extension> extensions; - private List<Category> categories; - private Map<String, Object> metadata; - - private CombinedQuarkusPlatformDescriptor(Builder builder) { - if (builder.platforms.isEmpty()) { - throw new IllegalArgumentException("No platforms to combine"); - } - master = builder.platforms.get(0); - platforms = new ArrayList<>(builder.platforms); - } - - @Override - public String getBomGroupId() { - return master.getBomGroupId(); - } - - @Override - public String getBomArtifactId() { - return master.getBomArtifactId(); - } - - @Override - public String getBomVersion() { - return master.getBomVersion(); - } - - @Override - public String getQuarkusVersion() { - return master.getQuarkusVersion(); - } - - @Override - public Map<String, Object> getMetadata() { - if (this.metadata != null) { - return this.metadata; - } - Map<String, Object> metadata = new LinkedHashMap<>(); - for (int i = platforms.size() - 1; i >= 0; i--) { - metadata.putAll(platforms.get(i).getMetadata()); - } - return this.metadata = metadata; - } - - @Override - public List<Extension> getExtensions() { - if (extensions != null) { - return extensions; - } - final List<Extension> list = new ArrayList<>(); - final Set<DepKey> depKeys = new HashSet<>(); - for (QuarkusPlatformDescriptor platform : platforms) { - for (Extension ext : platform.getExtensions()) { - if (depKeys.add(new DepKey(ext.getGroupId(), ext.getArtifactId()))) { - list.add(ext); - } - } - } - return extensions = list; - } - - @Override - public List<Category> getCategories() { - if (categories != null) { - return categories; - } - final List<Category> list = new ArrayList<>(); - final Set<String> ids = new HashSet<>(); - for (QuarkusPlatformDescriptor platform : platforms) { - for (Category cat : platform.getCategories()) { - if (ids.add(cat.getId())) { - list.add(cat); - } - } - } - return categories = list; - } - - @Override - public String getTemplate(String name) { - for (QuarkusPlatformDescriptor platform : platforms) { - final String template = platform.getTemplate(name); - if (template != null) { - return template; - } - } - return null; - } - - @Override - public <T> T loadResource(String name, ResourceInputStreamConsumer<T> consumer) throws IOException { - for (QuarkusPlatformDescriptor platform : platforms) { - try { - return platform.loadResource(name, consumer); - } catch (IOException e) { - // ignore - } - } - throw new IOException("Failed to locate resource " + name); - } - - @Override - public <T> T loadResourceAsPath(String name, ResourcePathConsumer<T> consumer) throws IOException { - for (QuarkusPlatformDescriptor platform : platforms) { - try { - return platform.loadResourceAsPath(name, consumer); - } catch (IOException e) { - // ignore - } - } - throw new IOException("Failed to locate resource " + name); - } - - private static class DepKey { - final String groupId; - final String artifactId; - final String classifier; - final String type; - - DepKey(Dependency dep) { - this(dep.getGroupId(), dep.getArtifactId(), dep.getClassifier(), dep.getType()); - } - - DepKey(String groupId, String artifactId) { - this(groupId, artifactId, null, null); - } - - DepKey(String groupId, String artifactId, String classifier, String type) { - this.groupId = groupId; - this.artifactId = artifactId; - this.classifier = classifier; - this.type = type; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof DepKey)) { - return false; - } - DepKey depKey = (DepKey) o; - return Objects.equals(groupId, depKey.groupId) && - Objects.equals(artifactId, depKey.artifactId) && - Objects.equals(classifier, depKey.classifier) && - Objects.equals(type, depKey.type); - } - - @Override - public int hashCode() { - return Objects.hash(groupId, artifactId, classifier, type); - } - } -} diff --git a/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/platform/descriptor/QuarkusPlatformDescriptor.java b/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/platform/descriptor/QuarkusPlatformDescriptor.java deleted file mode 100644 index 811557e98d9ee6..00000000000000 --- a/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/platform/descriptor/QuarkusPlatformDescriptor.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.quarkus.platform.descriptor; - -import io.quarkus.dependencies.Category; -import io.quarkus.dependencies.Extension; -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import org.apache.maven.model.Dependency; - -public interface QuarkusPlatformDescriptor { - - String getBomGroupId(); - - String getBomArtifactId(); - - String getBomVersion(); - - String getQuarkusVersion(); - - /** - * - * @return platform's dependencyManagement - */ - default List<Dependency> getManagedDependencies() { - throw new UnsupportedOperationException(); - } - - List<Extension> getExtensions(); - - List<Category> getCategories(); - - default Map<String, Object> getMetadata() { - return Collections.emptyMap(); - } - - String getTemplate(String name); - - <T> T loadResource(String name, ResourceInputStreamConsumer<T> consumer) throws IOException; - - <T> T loadResourceAsPath(String name, ResourcePathConsumer<T> consumer) throws IOException; - - default String gav() { - return String.format("%s:%s:%s", getBomGroupId(), getBomArtifactId(), getBomVersion()); - } - -} diff --git a/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/platform/descriptor/loader/QuarkusPlatformDescriptorLoader.java b/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/platform/descriptor/loader/QuarkusPlatformDescriptorLoader.java deleted file mode 100644 index 371085940126f1..00000000000000 --- a/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/platform/descriptor/loader/QuarkusPlatformDescriptorLoader.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.quarkus.platform.descriptor.loader; - -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; - -public interface QuarkusPlatformDescriptorLoader<D extends QuarkusPlatformDescriptor, C extends QuarkusPlatformDescriptorLoaderContext> { - - D load(C context); -} diff --git a/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/platform/descriptor/loader/QuarkusPlatformDescriptorLoaderContext.java b/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/platform/descriptor/loader/QuarkusPlatformDescriptorLoaderContext.java deleted file mode 100644 index 2486051b955bc1..00000000000000 --- a/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/platform/descriptor/loader/QuarkusPlatformDescriptorLoaderContext.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.quarkus.platform.descriptor.loader; - -import io.quarkus.devtools.messagewriter.MessageWriter; - -public interface QuarkusPlatformDescriptorLoaderContext { - - MessageWriter getMessageWriter(); -} diff --git a/independent-projects/tools/platform-descriptor-api/src/test/java/io/quarkus/dependencies/ExtensionPredicateTest.java b/independent-projects/tools/platform-descriptor-api/src/test/java/io/quarkus/dependencies/ExtensionPredicateTest.java deleted file mode 100644 index 7f9e27f90d6c07..00000000000000 --- a/independent-projects/tools/platform-descriptor-api/src/test/java/io/quarkus/dependencies/ExtensionPredicateTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.quarkus.dependencies; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.jupiter.api.Test; - -class ExtensionPredicateTest { - - @Test - void rejectUnlisted() { - ExtensionPredicate predicate = new ExtensionPredicate("foo"); - Extension extension = new Extension("g", "a", "v"); - extension.setUnlisted(true); - assertThat(predicate).rejects(extension); - } - - @Test - void acceptKeywordInArtifactId() { - ExtensionPredicate predicate = new ExtensionPredicate("foo"); - Extension extension = new Extension("g", "foo-bar", "1.0"); - assertThat(predicate).accepts(extension); - } - - @Test - void acceptKeywordInLabel() { - ExtensionPredicate predicate = new ExtensionPredicate("foo"); - Extension extension = new Extension("g", "a", "1.0"); - extension.setKeywords(new String[] { "foo", "bar" }); - assertThat(predicate).accepts(extension); - } - -} diff --git a/independent-projects/tools/platform-descriptor-resolver-json/src/main/java/io/quarkus/platform/descriptor/resolver/json/ChainedJsonDescriptorResolver.java b/independent-projects/tools/platform-descriptor-resolver-json/src/main/java/io/quarkus/platform/descriptor/resolver/json/ChainedJsonDescriptorResolver.java deleted file mode 100644 index b8aee2e838158c..00000000000000 --- a/independent-projects/tools/platform-descriptor-resolver-json/src/main/java/io/quarkus/platform/descriptor/resolver/json/ChainedJsonDescriptorResolver.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.quarkus.platform.descriptor.resolver.json; - -import io.quarkus.devtools.messagewriter.MessageWriter; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; - -public class ChainedJsonDescriptorResolver implements JsonDescriptorResolver { - - private final List<JsonDescriptorResolver> chain; - - public ChainedJsonDescriptorResolver(JsonDescriptorResolver... descriptorResolvers) { - chain = Arrays.asList(descriptorResolvers); - } - - @Override - public Path jsonForBom(String bomGroupId, String bomArtifactId, String bomVersion, - JsonMavenArtifactResolver artifactResolver, MessageWriter log) - throws Exception { - for (JsonDescriptorResolver resolver : chain) { - try { - final Path p = resolver.jsonForBom(bomGroupId, bomArtifactId, bomVersion, artifactResolver, log); - if (p != null) { - return p; - } - } catch (Exception e) { - if (log != null) { - log.debug("Failed to resolve Quarkus platform descriptor for BOM %s:%s:%s: %s", bomGroupId, bomArtifactId, - bomVersion, e.getLocalizedMessage()); - } - } - } - throw new Exception( - "Failed to resolve the JSON descriptor for BOM " + bomGroupId + ":" + bomArtifactId + ":" + bomVersion); - } -} diff --git a/independent-projects/tools/platform-descriptor-resolver-json/src/main/java/io/quarkus/platform/descriptor/resolver/json/JsonDescriptorResolver.java b/independent-projects/tools/platform-descriptor-resolver-json/src/main/java/io/quarkus/platform/descriptor/resolver/json/JsonDescriptorResolver.java deleted file mode 100644 index c7797b674f5c66..00000000000000 --- a/independent-projects/tools/platform-descriptor-resolver-json/src/main/java/io/quarkus/platform/descriptor/resolver/json/JsonDescriptorResolver.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.quarkus.platform.descriptor.resolver.json; - -import io.quarkus.devtools.messagewriter.MessageWriter; -import java.nio.file.Path; - -public interface JsonDescriptorResolver { - - Path jsonForBom(String bomGroupId, String bomArtifactId, String bomVersion, JsonMavenArtifactResolver jsonResolver, - MessageWriter log) throws Exception; -} diff --git a/independent-projects/tools/platform-descriptor-resolver-json/src/main/java/io/quarkus/platform/descriptor/resolver/json/JsonMavenArtifactResolver.java b/independent-projects/tools/platform-descriptor-resolver-json/src/main/java/io/quarkus/platform/descriptor/resolver/json/JsonMavenArtifactResolver.java deleted file mode 100644 index 25b7a6518505bc..00000000000000 --- a/independent-projects/tools/platform-descriptor-resolver-json/src/main/java/io/quarkus/platform/descriptor/resolver/json/JsonMavenArtifactResolver.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.quarkus.platform.descriptor.resolver.json; - -import io.quarkus.devtools.messagewriter.MessageWriter; -import java.nio.file.Path; - -public interface JsonMavenArtifactResolver { - - Path resolveArtifact(String groupId, String artifactId, String classifier, String type, String version, MessageWriter log) - throws Exception; -} diff --git a/independent-projects/tools/platform-descriptor-resolver-json/src/main/java/io/quarkus/platform/descriptor/resolver/json/PlatformDescriptorLoadingException.java b/independent-projects/tools/platform-descriptor-resolver-json/src/main/java/io/quarkus/platform/descriptor/resolver/json/PlatformDescriptorLoadingException.java deleted file mode 100644 index f661ccdca9e182..00000000000000 --- a/independent-projects/tools/platform-descriptor-resolver-json/src/main/java/io/quarkus/platform/descriptor/resolver/json/PlatformDescriptorLoadingException.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.quarkus.platform.descriptor.resolver.json; - -import java.lang.Exception; - -public class PlatformDescriptorLoadingException extends Exception { - - private static final long serialVersionUID = 1L; - - public PlatformDescriptorLoadingException(String message, Throwable cause) { - super(message, cause); - } - - public PlatformDescriptorLoadingException(String message) { - super(message); - } -} diff --git a/independent-projects/tools/platform-descriptor-resolver-json/src/main/java/io/quarkus/platform/descriptor/resolver/json/QuarkusJsonPlatformDescriptorResolver.java b/independent-projects/tools/platform-descriptor-resolver-json/src/main/java/io/quarkus/platform/descriptor/resolver/json/QuarkusJsonPlatformDescriptorResolver.java deleted file mode 100644 index 406b018e54fb17..00000000000000 --- a/independent-projects/tools/platform-descriptor-resolver-json/src/main/java/io/quarkus/platform/descriptor/resolver/json/QuarkusJsonPlatformDescriptorResolver.java +++ /dev/null @@ -1,738 +0,0 @@ -package io.quarkus.platform.descriptor.resolver.json; - -import static io.quarkus.platform.tools.ToolsUtils.getProperty; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.quarkus.bootstrap.BootstrapConstants; -import io.quarkus.bootstrap.model.AppArtifact; -import io.quarkus.bootstrap.resolver.AppModelResolver; -import io.quarkus.bootstrap.resolver.AppModelResolverException; -import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver; -import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; -import io.quarkus.devtools.messagewriter.MessageWriter; -import io.quarkus.maven.utilities.MojoUtils; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.descriptor.loader.json.ArtifactResolver; -import io.quarkus.platform.descriptor.loader.json.ClassPathResourceLoader; -import io.quarkus.platform.descriptor.loader.json.DirectoryResourceLoader; -import io.quarkus.platform.descriptor.loader.json.QuarkusJsonPlatformDescriptorLoader; -import io.quarkus.platform.descriptor.loader.json.QuarkusJsonPlatformDescriptorLoaderContext; -import io.quarkus.platform.descriptor.loader.json.ResourceLoader; -import io.quarkus.platform.descriptor.loader.json.ZipResourceLoader; -import io.quarkus.platform.tools.ToolsConstants; -import io.quarkus.platform.tools.ToolsUtils; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Iterator; -import java.util.Properties; -import java.util.ServiceLoader; -import java.util.function.Function; -import org.apache.commons.lang3.StringUtils; -import org.apache.maven.model.Model; -import org.apache.maven.model.Parent; - -/** - * Helps resolve the specific or the latest available version of a JSON platform descriptor. - */ -public class QuarkusJsonPlatformDescriptorResolver { - - private static final String BUNDLED_QUARKUS_BOM_PATH = "quarkus-bom/pom.xml"; - private static final String BUNDLED_QUARKUS_PROPERTIES_PATH = "quarkus.properties"; - private static final String BUNDLED_EXTENSIONS_JSON_PATH = "quarkus-bom-descriptor/extensions.json"; - - private static final String QUARKUS_PLATFORM_DESCRIPTOR_JSON = "quarkus-platform-descriptor-json"; - - private static final String DEFAULT_QUARKUS_PLATFORM_VERSION_RANGE = "[1.0.0.CR2,2)"; - private static final String DEFAULT_NON_QUARKUS_VERSION_RANGE = "[0,)"; - - public static final String PROP_PLATFORM_JSON_GROUP_ID = "quarkus.platform.json.groupId"; - public static final String PROP_PLATFORM_JSON_ARTIFACT_ID = "quarkus.platform.json.artifactId"; - public static final String PROP_PLATFORM_JSON_VERSION = "quarkus.platform.json.version"; - public static final String PROP_PLATFORM_JSON_VERSION_RANGE = "quarkus.platform.json.version-range"; - - private static final JsonDescriptorResolver jsonDescriptorResolver; - static { - jsonDescriptorResolver = new ChainedJsonDescriptorResolver( - ((bomGroupId, bomArtifactId, bomVersion, jsonResolver, log) -> jsonResolver.resolveArtifact(bomGroupId, - bomArtifactId + BootstrapConstants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX, bomVersion, "json", - bomVersion, log)), - ((bomGroupId, bomArtifactId, bomVersion, jsonResolver, log) -> jsonResolver.resolveArtifact(bomGroupId, - bomArtifactId, null, "json", bomVersion, log)), - ((bomGroupId, bomArtifactId, bomVersion, jsonResolver, log) -> jsonResolver.resolveArtifact(bomGroupId, - bomArtifactId + "-descriptor-json", null, "json", bomVersion, log))); - } - - public static JsonDescriptorResolver jsonDescriptorResolver() { - return jsonDescriptorResolver; - } - - public static QuarkusJsonPlatformDescriptorResolver newInstance() { - return new QuarkusJsonPlatformDescriptorResolver(); - } - - private static String getDefaultVersionRange(String groupId, String artifactId) { - return ToolsConstants.IO_QUARKUS.equals(groupId) - && (isDefaultArtifactId(artifactId, "quarkus-bom") - || isDefaultArtifactId(artifactId, "quarkus-universe-bom") - || "quarkus-bom-descriptor".equals(artifactId)) - ? DEFAULT_QUARKUS_PLATFORM_VERSION_RANGE - : DEFAULT_NON_QUARKUS_VERSION_RANGE; - } - - private static boolean isDefaultArtifactId(String artifactId, String defaultPrefix) { - return artifactId.equals(defaultPrefix + BootstrapConstants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX) - || artifactId.equals(defaultPrefix); - } - - private String jsonGroupId; - private String jsonArtifactId; - private String jsonClassifier; - private String jsonVersion; - private String jsonVersionRange; - - private Path jsonDescriptor; - - private String bomGroupId; - private String bomArtifactId; - private String bomVersion; - private String bomVersionRange; - - private AppModelResolver artifactResolver; - private MessageWriter log; - - public QuarkusJsonPlatformDescriptorResolver() { - } - - public QuarkusPlatformDescriptor resolveFromJson(String groupId, String artifactId, String version) { - // for backward compatibility the classifier here is an empty string - return resolveFromJson(groupId, artifactId, "", version); - } - - public QuarkusPlatformDescriptor resolveFromJson(String groupId, String artifactId, String classifier, String version) { - this.jsonGroupId = groupId; - this.jsonArtifactId = artifactId; - this.jsonClassifier = classifier; - this.jsonVersion = version; - return resolve(); - } - - public QuarkusPlatformDescriptor resolveLatestFromJson(String groupId, String artifactId, String versionRange) { - // for backward compatibility the classifier here is an empty string - return resolveLatestFromJson(groupId, artifactId, "", versionRange); - } - - public QuarkusPlatformDescriptor resolveLatestFromJson(String groupId, String artifactId, String classifier, - String versionRange) { - this.jsonGroupId = groupId; - this.jsonArtifactId = artifactId; - this.jsonClassifier = classifier; - this.jsonVersionRange = versionRange; - return resolve(); - } - - public QuarkusPlatformDescriptor resolveFromJsonArtifactId(String artifactId) { - this.jsonArtifactId = artifactId; - return resolve(); - } - - public QuarkusPlatformDescriptor resolveFromJson(Path jsonDescriptor) { - this.jsonDescriptor = jsonDescriptor; - return resolve(); - } - - public QuarkusPlatformDescriptor resolveFromBom(String groupId, String artifactId, String version) { - this.bomGroupId = groupId; - this.bomArtifactId = artifactId; - this.bomVersion = version; - return resolve(); - } - - public QuarkusPlatformDescriptor resolveLatestFromBom(String groupId, String artifactId, String versionRange) { - this.bomGroupId = groupId; - this.bomArtifactId = artifactId; - this.bomVersionRange = versionRange; - return resolve(); - } - - public QuarkusJsonPlatformDescriptorResolver setArtifactResolver(AppModelResolver artifactResolver) { - this.artifactResolver = artifactResolver; - return this; - } - - public QuarkusJsonPlatformDescriptorResolver setMessageWriter(MessageWriter msgWriter) { - this.log = msgWriter; - return this; - } - - public QuarkusPlatformDescriptor resolve() { - - ensureLoggerInitialized(); - - AppModelResolver artifactResolver = this.artifactResolver; - if (artifactResolver == null) { - try { - artifactResolver = new BootstrapAppModelResolver(MavenArtifactResolver.builder().build()); - } catch (Exception e) { - throw new IllegalStateException("Failed to initialize the Maven artifact resolver", e); - } - } - - try { - if (jsonDescriptor != null) { - return loadFromFile(artifactResolver, jsonDescriptor); - } - return resolveJsonDescriptor(artifactResolver); - } catch (VersionNotAvailableException | PlatformDescriptorLoadingException e) { - throw new IllegalStateException("Failed to load Quarkus platform descriptor", e); - } - } - - public QuarkusPlatformDescriptor resolveBundled() { - ensureLoggerInitialized(); - final Model bundledBom = loadBundledPom(); - if (bundledBom == null) { - throw new IllegalStateException("Failed to locate bundled Quarkus platform BOM on the classpath"); - } - try { - return loadFromBomCoords(null, getGroupId(bundledBom), getArtifactId(bundledBom), getVersion(bundledBom), - bundledBom); - } catch (Exception e) { - throw new IllegalStateException("Failed to load bundled Quarkus platform", e); - } - } - - private void ensureLoggerInitialized() { - if (log == null) { - log = MessageWriter.info(); - } - } - - private QuarkusPlatformDescriptor loadFromFile(AppModelResolver artifactResolver, Path jsonFile) - throws PlatformDescriptorLoadingException, VersionNotAvailableException { - log.debug("Loading Quarkus platform descriptor from %s", jsonFile); - if (!Files.exists(jsonFile)) { - throw new IllegalArgumentException("Failed to locate extensions JSON file at " + jsonFile); - } - - // Resolve the Quarkus version used by the platform - final String quarkusCoreVersion; - try (BufferedReader reader = Files.newBufferedReader(jsonFile)) { - JsonNode node = new ObjectMapper().readTree(reader); - quarkusCoreVersion = node.get("quarkus-core-version").asText(null); - if (quarkusCoreVersion == null) { - throw new IllegalStateException("Failed to determine the Quarkus Core version for " + jsonFile); - } - } catch (RuntimeException | IOException e) { - throw new PlatformDescriptorLoadingException("Failed to parse extensions JSON file " + jsonFile, e); - } - log.debug("Loaded Quarkus platform is based on Quarkus %s", quarkusCoreVersion); - - try (InputStream is = Files.newInputStream(jsonFile)) { - return loadPlatformDescriptor(toLoaderResolver(artifactResolver), is, quarkusCoreVersion); - } catch (VersionNotAvailableException e) { - throw e; - } catch (Exception e) { - throw new PlatformDescriptorLoadingException("Failed to load Quarkus platform descriptor from " + jsonFile, e); - } - } - - private QuarkusPlatformDescriptor resolveJsonDescriptor(AppModelResolver artifactResolver) - throws PlatformDescriptorLoadingException { - if (!ToolsUtils.isNullOrEmpty(bomGroupId) || !ToolsUtils.isNullOrEmpty(bomArtifactId) - || !ToolsUtils.isNullOrEmpty(bomVersion) || !ToolsUtils.isNullOrEmpty(bomVersionRange)) { - if (log.isDebugEnabled()) { - final StringBuilder buf = new StringBuilder(); - buf.append("Resolving Quarkus platform descriptor from the provided BOM coordinates "); - appendArg(buf, bomGroupId); - buf.append(":"); - appendArg(buf, bomArtifactId); - buf.append(":"); - if (!ToolsUtils.isNullOrEmpty(bomVersion)) { - appendArg(buf, bomVersion); - } else if (!ToolsUtils.isNullOrEmpty(bomVersionRange)) { - appendArg(buf, bomVersionRange); - } else { - appendArg(buf, bomVersion); - } - log.debug(buf.toString()); - } - return resolveJsonArtifactFromBom(artifactResolver); - } - try { - return resolveJsonArtifactFromArgs(artifactResolver); - } catch (VersionNotAvailableException e) { - final QuarkusPlatformDescriptor platform = resolveJsonArtifactFromBom(artifactResolver); - log.warn(e.getLocalizedMessage() + ", falling back to the bundled platform based on " + platform.getBomGroupId() - + ":" + platform.getBomArtifactId() + "::pom:" + platform.getBomVersion() + " and Quarkus version " - + platform.getQuarkusVersion()); - return platform; - } - } - - private static void appendArg(StringBuilder buf, String arg) { - buf.append(ToolsUtils.isNullOrEmpty(arg) ? "<not-provided>" : arg); - } - - private QuarkusPlatformDescriptor resolveJsonArtifactFromArgs(AppModelResolver artifactResolver) - throws VersionNotAvailableException { - String jsonGroupId = this.jsonGroupId; - String jsonArtifactId = this.jsonArtifactId; - String jsonClassifier = this.jsonClassifier; - String jsonVersion = this.jsonVersion; - // If some of the coordinates are missing, we are trying the default ones - int defaultCoords = 0; - if (jsonGroupId == null) { - jsonGroupId = getProperty(PROP_PLATFORM_JSON_GROUP_ID); - if (jsonGroupId == null) { - jsonGroupId = ToolsConstants.DEFAULT_PLATFORM_BOM_GROUP_ID; - ++defaultCoords; - } - } - boolean artifactIdProvided = jsonArtifactId != null; - if (!artifactIdProvided) { - jsonArtifactId = getProperty(PROP_PLATFORM_JSON_ARTIFACT_ID); - artifactIdProvided = jsonArtifactId != null; - if (!artifactIdProvided) { - jsonArtifactId = ToolsConstants.DEFAULT_PLATFORM_BOM_ARTIFACT_ID; - ++defaultCoords; - } - } - boolean versionProvided = jsonVersion != null; - if (!versionProvided) { - if (jsonVersionRange != null) { - // if the range was set using the api, it overrides a possibly set version system property - // depending on how this evolves this may or may not be reasonable - try { - jsonVersion = resolveLatestJsonVersion(artifactResolver, jsonGroupId, jsonArtifactId, jsonVersionRange); - } catch (VersionNotAvailableException e) { - throw new IllegalStateException("Failed to resolve the latest version of " + jsonGroupId + ":" - + jsonArtifactId + " from the requested range " + jsonVersionRange, e); - } - versionProvided = true; - } else { - jsonVersion = getProperty(PROP_PLATFORM_JSON_VERSION); - versionProvided = jsonVersion != null; - if (!versionProvided) { - jsonVersion = resolveLatestJsonVersion(artifactResolver, jsonGroupId, jsonArtifactId, null); - ++defaultCoords; - } - } - } - if (jsonClassifier == null) { - jsonClassifier = jsonVersion; - } - final AppArtifact jsonArtifact = new AppArtifact(jsonGroupId, jsonArtifactId, jsonClassifier, "json", jsonVersion); - if (artifactIdProvided) { - try { - return loadFromFile(artifactResolver, artifactResolver.resolve(jsonArtifact)); - } catch (PlatformDescriptorLoadingException e) { - // the artifact was successfully resolved but processing of it has failed - throw new IllegalStateException("Failed to load Quarkus platform descriptor " + jsonArtifact, e); - } catch (Exception e) { - if (!versionProvided && e instanceof VersionNotAvailableException) { - throw (VersionNotAvailableException) e; - } - throw new IllegalStateException("Failed to resolve Quarkus platform descriptor " + jsonArtifact, e); - } - } - try { - return loadDescriptorForBom(artifactResolver, jsonArtifact); - } catch (VersionNotAvailableException e) { - if (defaultCoords == 3) { - // complete coords were the default ones, so we can re-throw and try the bundled platform - throw e; - } - throw new IllegalStateException("Failed to resolve the JSON artifact with the requested coordinates", e); - } - } - - private QuarkusPlatformDescriptor resolveJsonArtifactFromBom(AppModelResolver artifactResolver) - throws PlatformDescriptorLoadingException { - - // If some of the coordinates are missing, we are trying the default ones - boolean tryingDefaultCoords = false; - String bomGroupId = this.bomGroupId; - if (bomGroupId == null) { - bomGroupId = ToolsConstants.DEFAULT_PLATFORM_BOM_GROUP_ID; - tryingDefaultCoords = true; - } - String bomArtifactId = this.bomArtifactId; - if (bomArtifactId == null) { - bomArtifactId = ToolsConstants.DEFAULT_PLATFORM_BOM_ARTIFACT_ID; - tryingDefaultCoords = true; - } - String bomVersion = this.bomVersion; - try { - return loadFromBomCoords(artifactResolver, bomGroupId, bomArtifactId, bomVersion, null); - } catch (VersionNotAvailableException e) { - if (!tryingDefaultCoords) { - throw new IllegalStateException("Failed to resolve the platform BOM using the provided coordinates", e); - } - log.debug( - "Failed to resolve Quarkus platform BOM using the default coordinates %s:%s:%s, falling back to the bundled Quarkus platform artifacts", - bomGroupId, bomArtifactId, bomVersion); - } - - Model bundledBom = loadBundledPom(); - bomGroupId = this.bomGroupId; - if (bomGroupId != null) { - if (!bomGroupId.equals(getGroupId(bundledBom))) { - throw new IllegalStateException( - "Failed to resolve Quarkus platform using the requested BOM groupId " + bomGroupId); - } - } else { - bomGroupId = getGroupId(bundledBom); - } - if (bomGroupId == null) { - failedDetermineDefaultPlatformCoords(); - } - - bomArtifactId = this.bomArtifactId; - if (bomArtifactId != null) { - if (!bomArtifactId.equals(getArtifactId(bundledBom))) { - throw new IllegalStateException( - "Failed to resolve Quarkus platform using the requested BOM artifactId " + bomArtifactId); - } - } else { - bomArtifactId = getArtifactId(bundledBom); - } - if (bomArtifactId == null) { - failedDetermineDefaultPlatformCoords(); - } - - bomVersion = this.bomVersion; - if (bomVersion != null) { - if (!bomVersion.equals(getVersion(bundledBom))) { - throw new IllegalStateException( - "Failed to resolve Quarkus platform using the requested BOM version " + bomVersion); - } - } else if (this.bomVersionRange == null) { - bomVersion = getVersion(bundledBom); - } - try { - return loadFromBomCoords(artifactResolver, bomGroupId, bomArtifactId, bomVersion, bundledBom); - } catch (VersionNotAvailableException e) { - // this should never happen - throw new IllegalStateException("Failed to load the bundled platform artifacts", e); - } - } - - private QuarkusPlatformDescriptor loadFromBomCoords(AppModelResolver artifactResolver, String bomGroupId, - String bomArtifactId, String bomVersion, Model bundledBom) - throws PlatformDescriptorLoadingException, VersionNotAvailableException { - if (bomVersion == null) { - String bomVersionRange = this.bomVersionRange; - if (bomVersionRange == null) { - bomVersionRange = getDefaultVersionRange(bomGroupId, bomArtifactId); - } - final AppArtifact bomArtifact = new AppArtifact(bomGroupId, bomArtifactId, null, "pom", bomVersionRange); - log.debug("Resolving the latest version of %s", bomArtifact); - try { - bomVersion = artifactResolver.getLatestVersionFromRange(bomArtifact, bomVersionRange); - } catch (AppModelResolverException e) { - throw new VersionNotAvailableException("Failed to resolve the latest version of " + bomArtifact, e); - } - if (bomVersion == null) { - throw new VersionNotAvailableException("Failed to resolve the latest version of " + bomArtifact); - } - } - log.debug("Resolving Quarkus platform BOM %s:%s::pom:%s", bomGroupId, bomArtifactId, bomVersion); - - final Model theBundledBom = loadBundledPomIfNull(bundledBom); - // Check whether the BOM on the classpath is matching the requested one - if (theBundledBom != null - && bomArtifactId.equals(getArtifactId(theBundledBom)) - && bomVersion.equals(getVersion(theBundledBom)) - && bomGroupId.equals(getGroupId(theBundledBom))) { - log.debug("The requested Quarkus platform BOM version is available on the classpath"); - // If the BOM matches, there should also be the JSON file - final InputStream jsonStream = getCpResourceAsStream(BUNDLED_EXTENSIONS_JSON_PATH); - if (jsonStream != null) { - // The JSON is available, now there also should be quarkus.properties - final String quarkusVersion = getBundledPlatformQuarkusVersionOrNull(); - if (quarkusVersion != null) { - return loadPlatformDescriptor(getBundledResolver(theBundledBom), jsonStream, quarkusVersion); - } else { - log.debug("Failed to locate quarkus.properties on the classpath"); - } - } else { - log.debug("Failed to locate Quarkus platform descriptor on the classpath"); - } - } - - return loadDescriptorForBom(artifactResolver, new AppArtifact(bomGroupId, bomArtifactId, null, "json", bomVersion)); - } - - private void failedDetermineDefaultPlatformCoords() { - throw new IllegalStateException("Failed to determine the Maven coordinates of the default Quarkus platform"); - } - - private QuarkusPlatformDescriptor loadDescriptorForBom(AppModelResolver artifactResolver, AppArtifact jsonArtifact) - throws VersionNotAvailableException { - final Path jsonFile; - try { - jsonFile = jsonDescriptorResolver.jsonForBom(jsonArtifact.getGroupId(), jsonArtifact.getArtifactId(), - jsonArtifact.getVersion(), - (groupId, artifactId, classifier, type, version, log) -> { - log.debug("Attempting to resolve Quarkus platform descriptor %s:%s:%s:%s:%s", groupId, - artifactId, classifier == null ? "" : classifier, type, version); - return artifactResolver - .resolve(new AppArtifact(groupId, artifactId, classifier, type, version)); - }, - log); - } catch (Exception e) { - throw new VersionNotAvailableException("Failed to resolve Quarkus platform descriptor for BOM " + jsonArtifact, e); - } - try { - return loadFromFile(artifactResolver, jsonFile); - } catch (PlatformDescriptorLoadingException e) { - throw new IllegalStateException("Failed to load Quarkus platform descriptor " + jsonFile, e); - } - } - - @SuppressWarnings("rawtypes") - private QuarkusPlatformDescriptor loadPlatformDescriptor(ArtifactResolver mvn, final InputStream jsonStream, - String quarkusCoreVersion) throws PlatformDescriptorLoadingException, VersionNotAvailableException { - - ClassLoader jsonDescrLoaderCl = null; - - // check whether the quarkus-platform-descriptor-json used in the platform is already on the classpath - final String pomPropsPath = "META-INF/maven/" + ToolsConstants.IO_QUARKUS + "/" + QUARKUS_PLATFORM_DESCRIPTOR_JSON - + "/pom.properties"; - final InputStream is = getCpResourceAsStream(pomPropsPath); - if (is != null) { - final Properties props = new Properties(); - try { - props.load(is); - } catch (IOException e) { - throw new PlatformDescriptorLoadingException("Failed to load " + pomPropsPath + " from the classpath", e); - } - final String version = props.getProperty("version"); - if (quarkusCoreVersion.equals(version)) { - jsonDescrLoaderCl = Thread.currentThread().getContextClassLoader(); - } else { - log.debug("Version of the Quarkus JSON platform descriptor loader on the classpath is %s", version); - } - } - - // platform resource loader - ResourceLoader resourceLoader = null; - - boolean externalLoader = false; - if (jsonDescrLoaderCl == null) { - final AppArtifact jsonDescrArtifact = new AppArtifact(ToolsConstants.IO_QUARKUS, QUARKUS_PLATFORM_DESCRIPTOR_JSON, - null, "jar", quarkusCoreVersion); - log.debug("Resolving Quarkus JSON platform descriptor loader %s", jsonDescrArtifact); - final URL jsonDescrUrl; - try { - final Path path = mvn.process(jsonDescrArtifact.getGroupId(), jsonDescrArtifact.getArtifactId(), - jsonDescrArtifact.getClassifier(), jsonDescrArtifact.getType(), jsonDescrArtifact.getVersion(), p -> { - return p; - }); - resourceLoader = Files.isDirectory(path) ? new DirectoryResourceLoader(path) : new ZipResourceLoader(path); - log.debug("Quarkus platform resources will be loaded from %s", path); - jsonDescrUrl = path.toUri().toURL(); - } catch (AppModelResolverException e) { - throw new VersionNotAvailableException("Failed to resolve " + jsonDescrArtifact, e); - } catch (Exception e) { - throw new PlatformDescriptorLoadingException("Failed to resolve " + jsonDescrArtifact, e); - } - jsonDescrLoaderCl = new URLClassLoader(new URL[] { jsonDescrUrl }, Thread.currentThread().getContextClassLoader()); - externalLoader = true; - } - - try { - final Iterator<QuarkusJsonPlatformDescriptorLoader> i = ServiceLoader - .load(QuarkusJsonPlatformDescriptorLoader.class, jsonDescrLoaderCl).iterator(); - if (!i.hasNext()) { - throw new PlatformDescriptorLoadingException( - "Failed to locate an implementation of " + QuarkusJsonPlatformDescriptorLoader.class.getName()); - } - final QuarkusJsonPlatformDescriptorLoader<?> jsonDescrLoader = i.next(); - if (i.hasNext()) { - throw new PlatformDescriptorLoadingException( - "Located more than one implementation of " + QuarkusJsonPlatformDescriptorLoader.class.getName()); - } - - try { - return jsonDescrLoader.load( - new QuarkusJsonPlatformDescriptorLoaderContext( - mvn, - resourceLoader == null ? new ClassPathResourceLoader() : resourceLoader, - log) { - @Override - public <T> T parseJson(Function<InputStream, T> parser) { - return parser.apply(jsonStream); - } - }); - } catch (Exception e) { - throw new PlatformDescriptorLoadingException("Failed to load Quarkus platform descriptor", e); - } - } finally { - if (externalLoader) { - try { - ((URLClassLoader) jsonDescrLoaderCl).close(); - } catch (IOException e) { - } - } - } - } - - private String resolveLatestJsonVersion(AppModelResolver artifactResolver, String groupId, String artifactId, - String versionRange) throws VersionNotAvailableException { - if (versionRange == null) { - versionRange = getProperty(PROP_PLATFORM_JSON_VERSION_RANGE); - if (versionRange == null) { - versionRange = getDefaultVersionRange(groupId, artifactId); - } - } - try { - return resolveLatestFromVersionRange(artifactResolver, groupId, artifactId, null, "json", versionRange); - } catch (AppModelResolverException e) { - throw new VersionNotAvailableException("Failed to resolve the latest JSON platform version of " + groupId + ":" - + artifactId + "::json:" + versionRange); - } - } - - private String resolveLatestFromVersionRange(AppModelResolver mvn, String groupId, String artifactId, String classifier, - String type, final String versionRange) - throws AppModelResolverException, VersionNotAvailableException { - final AppArtifact appArtifact = new AppArtifact(groupId, artifactId, classifier, type, versionRange); - log.debug("Resolving the latest version of %s", appArtifact); - final String latestVersion = mvn.getLatestVersionFromRange(appArtifact, versionRange); - if (latestVersion == null) { - throw new VersionNotAvailableException("Failed to resolve the latest version of " + appArtifact); - } - return latestVersion; - } - - private Model loadBundledPomIfNull(Model model) { - return model == null ? loadBundledPom() : model; - } - - private Model loadBundledPom() { - final InputStream bomIs = getCpResourceAsStream(BUNDLED_QUARKUS_BOM_PATH); - if (bomIs == null) { - log.debug("Failed to locate quarkus-bom/pom.xml on the classpath"); - return null; - } - try { - return MojoUtils.readPom(bomIs); - } catch (IOException e) { - throw new IllegalStateException("Failed to load POM model from the classpath for quarkus-bom/pom.xml", e); - } finally { - try { - bomIs.close(); - } catch (IOException e) { - } - } - } - - private static String getGroupId(Model model) { - if (model == null) { - return null; - } - String groupId = model.getGroupId(); - if (groupId != null) { - return groupId; - } - final Parent parent = model.getParent(); - if (parent != null) { - groupId = parent.getGroupId(); - if (groupId != null) { - return groupId; - } - } - throw new IllegalStateException("Failed to determine the groupId for the POM of " + model.getArtifactId()); - } - - private static String getArtifactId(Model model) { - if (model == null) { - return null; - } - return model.getArtifactId(); - } - - private static String getVersion(Model model) { - if (model == null) { - return null; - } - String version = model.getVersion(); - if (version != null) { - return version; - } - final Parent parent = model.getParent(); - if (parent != null) { - version = parent.getVersion(); - if (version != null) { - return version; - } - } - throw new IllegalStateException("Failed to determine the version for the POM of " + model.getArtifactId()); - } - - private ArtifactResolver toLoaderResolver(AppModelResolver mvn) { - return new ArtifactResolver() { - - @Override - public <T> T process(String groupId, String artifactId, String classifier, String type, String version, - Function<Path, T> processor) throws AppModelResolverException { - final AppArtifact artifact = new AppArtifact(groupId, artifactId, classifier, type, version); - return processor.apply(mvn.resolve(artifact)); - } - }; - } - - private ArtifactResolver getBundledResolver(final Model model) { - - final Path platformResources; - try { - platformResources = MojoUtils.getResourceOrigin(Thread.currentThread().getContextClassLoader(), - BUNDLED_QUARKUS_BOM_PATH); - } catch (IOException e) { - throw new IllegalStateException("Failed to locate the bundled Quarkus platform resources on the classpath"); - } - - final ArtifactResolver bundledResolver = new ArtifactResolver() { - - @Override - public <T> T process(String groupId, String artifactId, String classifier, String type, String version, - Function<Path, T> processor) { - if (QUARKUS_PLATFORM_DESCRIPTOR_JSON.equals(artifactId) - && ToolsConstants.IO_QUARKUS.equals(groupId) - && "jar".equals(type) - && StringUtils.isEmpty(classifier) - && version.equals(getBundledPlatformQuarkusVersionOrNull())) { - return processor.apply(platformResources); - } - throw new IllegalArgumentException("Unexpected artifact coordinates " + groupId + ":" + artifactId + ":" - + classifier + ":" + type + ":" + version); - } - }; - return bundledResolver; - } - - private static String getBundledPlatformQuarkusVersionOrNull() { - final InputStream quarkusPropsStream = getCpResourceAsStream(BUNDLED_QUARKUS_PROPERTIES_PATH); - if (quarkusPropsStream == null) { - return null; - } - final Properties props = new Properties(); - try { - props.load(quarkusPropsStream); - } catch (IOException e) { - throw new IllegalStateException("Failed to load quarkus.properties from the classpath", e); - } - return ToolsUtils.requireQuarkusCoreVersion(props); - } - - private static InputStream getCpResourceAsStream(String name) { - return Thread.currentThread().getContextClassLoader().getResourceAsStream(name); - } -} diff --git a/independent-projects/tools/platform-descriptor-resolver-json/src/main/java/io/quarkus/platform/descriptor/resolver/json/VersionNotAvailableException.java b/independent-projects/tools/platform-descriptor-resolver-json/src/main/java/io/quarkus/platform/descriptor/resolver/json/VersionNotAvailableException.java deleted file mode 100644 index cea8276f639917..00000000000000 --- a/independent-projects/tools/platform-descriptor-resolver-json/src/main/java/io/quarkus/platform/descriptor/resolver/json/VersionNotAvailableException.java +++ /dev/null @@ -1,14 +0,0 @@ -package io.quarkus.platform.descriptor.resolver.json; - -public class VersionNotAvailableException extends Exception { - - private static final long serialVersionUID = 1L; - - public VersionNotAvailableException(String message, Throwable cause) { - super(message, cause); - } - - public VersionNotAvailableException(String message) { - super(message); - } -} diff --git a/independent-projects/tools/platform-descriptor-resolver-json/src/test/java/io/quarkus/platform/descriptor/resolver/json/test/QuarkusJsonPlatformDescriptorResolverTest.java b/independent-projects/tools/platform-descriptor-resolver-json/src/test/java/io/quarkus/platform/descriptor/resolver/json/test/QuarkusJsonPlatformDescriptorResolverTest.java deleted file mode 100644 index d077b1e4668815..00000000000000 --- a/independent-projects/tools/platform-descriptor-resolver-json/src/test/java/io/quarkus/platform/descriptor/resolver/json/test/QuarkusJsonPlatformDescriptorResolverTest.java +++ /dev/null @@ -1,208 +0,0 @@ -package io.quarkus.platform.descriptor.resolver.json.test; - -import static io.quarkus.platform.tools.ToolsConstants.DEFAULT_PLATFORM_BOM_ARTIFACT_ID; -import static io.quarkus.platform.tools.ToolsConstants.DEFAULT_PLATFORM_BOM_GROUP_ID; -import static io.quarkus.platform.tools.ToolsConstants.IO_QUARKUS; -import static io.quarkus.platform.tools.ToolsConstants.QUARKUS_CORE_ARTIFACT_ID; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import io.quarkus.bootstrap.BootstrapConstants; -import io.quarkus.bootstrap.model.AppArtifact; -import io.quarkus.bootstrap.resolver.ResolverSetupCleanup; -import io.quarkus.bootstrap.resolver.TsArtifact; -import io.quarkus.bootstrap.resolver.TsDependency; -import io.quarkus.bootstrap.util.IoUtils; -import io.quarkus.devtools.messagewriter.MessageWriter; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.descriptor.resolver.json.QuarkusJsonPlatformDescriptorResolver; -import io.quarkus.platform.tools.ToolsConstants; -import java.nio.file.Path; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class QuarkusJsonPlatformDescriptorResolverTest extends ResolverSetupCleanup { - - private static Path testDir; - - private MessageWriter log = MessageWriter.info(); - - @BeforeEach - @Override - public void setup() throws Exception { - if (workDir != null) { - return; - } - super.setup(); - testDir = workDir; - doSetup(); - } - - @Override - protected boolean cleanWorkDir() { - return false; - } - - @AfterAll - public static void afterAll() throws Exception { - if (testDir != null) { - IoUtils.recursiveDelete(testDir); - } - } - - protected void doSetup() throws Exception { - - final TsArtifact quarkusCore = new TsArtifact(IO_QUARKUS, QUARKUS_CORE_ARTIFACT_ID, null, "jar", "1.0.0.CR50"); - install(quarkusCore, newJar().getPath(workDir)); - - final TsArtifact quarkusPlatformDescriptorJson = new TsArtifact(IO_QUARKUS, "quarkus-platform-descriptor-json", null, - "jar", "1.0.0.CR50"); - install(quarkusPlatformDescriptorJson, newJar().getPath(workDir)); - - // install a few universe versions with the default GA - installDefaultUniverseLegacyArtifactId(quarkusCore, "1.0.0.CR50"); - installDefaultUniverseLegacyArtifactId(quarkusCore, "1.0.0.CR60"); - installDefaultUniverseLegacyArtifactId(quarkusCore, "1.0.0.CR70"); - - installDefaultUniverse(quarkusCore, "1.0.0.CR80"); - - // install a universe with a custom GA and JSON descriptor with `-descriptor-json` suffix - TsArtifact universeBom = new TsArtifact(DEFAULT_PLATFORM_BOM_GROUP_ID, "other-universe", null, "pom", "1.0.0.CR80") - .addManagedDependency(new TsDependency(quarkusCore)); - install(universeBom); - final TsArtifact universeJson = new TsArtifact(DEFAULT_PLATFORM_BOM_GROUP_ID, "other-universe" + "-descriptor-json", - null, "json", "1.0.0.CR80") - .setContent(new TestPlatformJsonDescriptorProvider(universeBom)); - install(universeJson); - } - - @Test - public void testResolveBundled() throws Exception { - final QuarkusPlatformDescriptor platform = newResolver().resolveBundled(); - assertBundledPlatform(platform, "1.0.0.CR90"); - assertEquals("1.0.0.CR90", platform.getQuarkusVersion()); - } - - @Test - public void testResolve() throws Exception { - final QuarkusPlatformDescriptor platform = newResolver().resolve(); - assertDefaultPlatform(platform, "1.0.0.CR80"); - assertEquals("1.0.0.CR50", platform.getQuarkusVersion()); - } - - @Test - public void testResolveFromJsonVersion() throws Exception { - final QuarkusPlatformDescriptor platform = newResolver().resolveFromJson(DEFAULT_PLATFORM_BOM_GROUP_ID, - DEFAULT_PLATFORM_BOM_ARTIFACT_ID, "1.0.0.CR60"); - assertDefaultPlatform(platform, "1.0.0.CR60"); - assertEquals("1.0.0.CR50", platform.getQuarkusVersion()); - } - - @Test - public void testResolveFromJsonFile() throws Exception { - final Path jsonPath = resolver.resolve( - new AppArtifact(DEFAULT_PLATFORM_BOM_GROUP_ID, DEFAULT_PLATFORM_BOM_ARTIFACT_ID, null, "json", "1.0.0.CR50")); - final QuarkusPlatformDescriptor platform = newResolver().resolveFromJson(jsonPath); - assertDefaultPlatform(platform, "1.0.0.CR50"); - assertEquals("1.0.0.CR50", platform.getQuarkusVersion()); - } - - @Test - public void testResolveFromBomWithDescriptorJsonPrefix() throws Exception { - final QuarkusPlatformDescriptor platform = newResolver().resolveFromBom(DEFAULT_PLATFORM_BOM_GROUP_ID, "other-universe", - "1.0.0.CR80"); - assertNotNull(platform); - assertEquals(ToolsConstants.IO_QUARKUS, platform.getBomGroupId()); - assertEquals("other-universe", platform.getBomArtifactId()); - assertEquals("1.0.0.CR80", platform.getBomVersion()); - assertEquals("1.0.0.CR50", platform.getQuarkusVersion()); - } - - @Test - public void testResolveFromJsonWithDescriptorJsonPrefix() throws Exception { - final QuarkusPlatformDescriptor platform = newResolver().resolveLatestFromJson(DEFAULT_PLATFORM_BOM_GROUP_ID, - "other-universe" + "-descriptor-json", null); - assertNotNull(platform); - assertEquals(ToolsConstants.IO_QUARKUS, platform.getBomGroupId()); - assertEquals("other-universe", platform.getBomArtifactId()); - assertEquals("1.0.0.CR80", platform.getBomVersion()); - assertEquals("1.0.0.CR50", platform.getQuarkusVersion()); - } - - @Test - public void testResolveFromLatestJson() throws Exception { - final QuarkusPlatformDescriptor platform = newResolver().resolveLatestFromJson(DEFAULT_PLATFORM_BOM_GROUP_ID, - DEFAULT_PLATFORM_BOM_ARTIFACT_ID + BootstrapConstants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX, null, null); - assertDefaultPlatform(platform, "1.0.0.CR80"); - assertEquals("1.0.0.CR50", platform.getQuarkusVersion()); - } - - @Test - public void testResolveFromLatestJsonWithRange() throws Exception { - final QuarkusPlatformDescriptor platform = newResolver().resolveLatestFromJson(DEFAULT_PLATFORM_BOM_GROUP_ID, - DEFAULT_PLATFORM_BOM_ARTIFACT_ID, "[0,1.0.0.CR60]"); - assertDefaultPlatform(platform, "1.0.0.CR60"); - assertEquals("1.0.0.CR50", platform.getQuarkusVersion()); - } - - @Test - public void testResolveFromLatestBom() throws Exception { - final QuarkusPlatformDescriptor platform = newResolver().resolveLatestFromBom(DEFAULT_PLATFORM_BOM_GROUP_ID, - DEFAULT_PLATFORM_BOM_ARTIFACT_ID, null); - assertDefaultPlatform(platform, "1.0.0.CR80"); - assertEquals("1.0.0.CR50", platform.getQuarkusVersion()); - } - - @Test - public void testResolveFromLatestBomWithRange() throws Exception { - final QuarkusPlatformDescriptor platform = newResolver().resolveLatestFromJson(DEFAULT_PLATFORM_BOM_GROUP_ID, - DEFAULT_PLATFORM_BOM_ARTIFACT_ID, "[0,1.0.0.CR60]"); - assertDefaultPlatform(platform, "1.0.0.CR60"); - assertEquals("1.0.0.CR50", platform.getQuarkusVersion()); - } - - private void installDefaultUniverseLegacyArtifactId(final TsArtifact quarkusCore, String platformVersion) { - final TsArtifact universeBom = new TsArtifact(DEFAULT_PLATFORM_BOM_GROUP_ID, DEFAULT_PLATFORM_BOM_ARTIFACT_ID, null, - "pom", platformVersion) - .addManagedDependency(new TsDependency(quarkusCore)); - install(universeBom); - final TsArtifact universeJson = new TsArtifact(DEFAULT_PLATFORM_BOM_GROUP_ID, DEFAULT_PLATFORM_BOM_ARTIFACT_ID, null, - "json", platformVersion) - .setContent(new TestPlatformJsonDescriptorProvider(universeBom)); - install(universeJson); - } - - private void installDefaultUniverse(final TsArtifact quarkusCore, String platformVersion) { - final TsArtifact universeBom = new TsArtifact(DEFAULT_PLATFORM_BOM_GROUP_ID, DEFAULT_PLATFORM_BOM_ARTIFACT_ID, null, - "pom", platformVersion) - .addManagedDependency(new TsDependency(quarkusCore)); - install(universeBom); - final TsArtifact universeJson = new TsArtifact(DEFAULT_PLATFORM_BOM_GROUP_ID, - DEFAULT_PLATFORM_BOM_ARTIFACT_ID + BootstrapConstants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX, - platformVersion, - "json", platformVersion) - .setContent(new TestPlatformJsonDescriptorProvider(universeBom)); - install(universeJson); - } - - private QuarkusJsonPlatformDescriptorResolver newResolver() { - return QuarkusJsonPlatformDescriptorResolver.newInstance() - .setMessageWriter(log) - .setArtifactResolver(resolver); - } - - private static void assertDefaultPlatform(QuarkusPlatformDescriptor platform, String version) { - assertNotNull(platform); - assertEquals(ToolsConstants.IO_QUARKUS, platform.getBomGroupId()); - assertEquals(ToolsConstants.DEFAULT_PLATFORM_BOM_ARTIFACT_ID, platform.getBomArtifactId()); - assertEquals(version, platform.getBomVersion()); - } - - private static void assertBundledPlatform(QuarkusPlatformDescriptor platform, String version) { - assertNotNull(platform); - assertEquals(ToolsConstants.IO_QUARKUS, platform.getBomGroupId()); - assertEquals("quarkus-bom", platform.getBomArtifactId()); - assertEquals(version, platform.getBomVersion()); - } -} diff --git a/independent-projects/tools/platform-descriptor-resolver-json/src/test/java/io/quarkus/platform/descriptor/resolver/json/test/TestJsonPlatformDescriptorLoader.java b/independent-projects/tools/platform-descriptor-resolver-json/src/test/java/io/quarkus/platform/descriptor/resolver/json/test/TestJsonPlatformDescriptorLoader.java deleted file mode 100644 index 8ccd665066d5fd..00000000000000 --- a/independent-projects/tools/platform-descriptor-resolver-json/src/test/java/io/quarkus/platform/descriptor/resolver/json/test/TestJsonPlatformDescriptorLoader.java +++ /dev/null @@ -1,81 +0,0 @@ -package io.quarkus.platform.descriptor.resolver.json.test; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.quarkus.dependencies.Category; -import io.quarkus.dependencies.Extension; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.descriptor.ResourceInputStreamConsumer; -import io.quarkus.platform.descriptor.ResourcePathConsumer; -import io.quarkus.platform.descriptor.loader.json.QuarkusJsonPlatformDescriptorLoader; -import io.quarkus.platform.descriptor.loader.json.QuarkusJsonPlatformDescriptorLoaderContext; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.List; - -public class TestJsonPlatformDescriptorLoader implements QuarkusJsonPlatformDescriptorLoader<QuarkusPlatformDescriptor> { - - @Override - public QuarkusPlatformDescriptor load(QuarkusJsonPlatformDescriptorLoaderContext context) { - final JsonNode json = context.parseJson(s -> { - try (InputStreamReader reader = new InputStreamReader(s, StandardCharsets.UTF_8)) { - return new ObjectMapper().readTree(reader); - } catch (IOException e) { - throw new IllegalStateException("Failed to parse JSON descriptor", e); - } - }); - - final JsonNode bom = json.required("bom"); - final String quarkusVersion = json.required("quarkus-core-version").asText(); - - return new QuarkusPlatformDescriptor() { - - @Override - public String getBomGroupId() { - return bom.get("groupId").asText(null); - } - - @Override - public String getBomArtifactId() { - return bom.get("artifactId").asText(null); - } - - @Override - public String getBomVersion() { - return bom.get("version").asText(null); - } - - @Override - public String getQuarkusVersion() { - return quarkusVersion; - } - - @Override - public List<Extension> getExtensions() { - return Collections.emptyList(); - } - - @Override - public List<Category> getCategories() { - return Collections.emptyList(); - } - - @Override - public String getTemplate(String name) { - return null; - } - - @Override - public <T> T loadResource(String name, ResourceInputStreamConsumer<T> consumer) throws IOException { - return null; - } - - @Override - public <T> T loadResourceAsPath(String name, ResourcePathConsumer<T> consumer) throws IOException { - return null; - } - }; - } -} diff --git a/independent-projects/tools/platform-descriptor-resolver-json/src/test/java/io/quarkus/platform/descriptor/resolver/json/test/TestPlatformJsonDescriptorProvider.java b/independent-projects/tools/platform-descriptor-resolver-json/src/test/java/io/quarkus/platform/descriptor/resolver/json/test/TestPlatformJsonDescriptorProvider.java deleted file mode 100644 index 77673dd52c427e..00000000000000 --- a/independent-projects/tools/platform-descriptor-resolver-json/src/test/java/io/quarkus/platform/descriptor/resolver/json/test/TestPlatformJsonDescriptorProvider.java +++ /dev/null @@ -1,52 +0,0 @@ -package io.quarkus.platform.descriptor.resolver.json.test; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import io.quarkus.bootstrap.resolver.TsArtifact; -import io.quarkus.platform.tools.ToolsConstants; -import java.io.BufferedWriter; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import org.apache.maven.model.Dependency; -import org.apache.maven.model.Model; - -public class TestPlatformJsonDescriptorProvider implements TsArtifact.ContentProvider { - - private final TsArtifact bomArtifact; - - public TestPlatformJsonDescriptorProvider(TsArtifact bomArtifact) { - this.bomArtifact = bomArtifact; - } - - @Override - public Path getPath(Path workDir) throws IOException { - final Model model = bomArtifact.getPomModel(); - - ObjectMapper mapper = new ObjectMapper(); - ObjectNode json = mapper.createObjectNode(); - json.set("bom", - mapper.createObjectNode().put("groupId", model.getGroupId()) - .put("artifactId", model.getArtifactId()) - .put("version", model.getVersion())); - - String coreVersion = null; - for (Dependency dep : model.getDependencyManagement().getDependencies()) { - if (dep.getArtifactId().equals(ToolsConstants.QUARKUS_CORE_ARTIFACT_ID) - && dep.getGroupId().equals(ToolsConstants.QUARKUS_CORE_GROUP_ID)) { - coreVersion = dep.getVersion(); - } - } - if (coreVersion == null) { - throw new IllegalStateException("Failed to locate " + ToolsConstants.QUARKUS_CORE_GROUP_ID + ":" - + ToolsConstants.QUARKUS_CORE_ARTIFACT_ID + " among the managed dependencies"); - } - json.put("quarkus-core-version", coreVersion); - - final Path jsonPath = workDir.resolve(bomArtifact.getArtifactFileName()); - try (BufferedWriter writer = Files.newBufferedWriter(jsonPath)) { - mapper.writeValue(writer, json); - } - return jsonPath; - } -} diff --git a/independent-projects/tools/platform-descriptor-resolver-json/src/test/resources/META-INF/services/io.quarkus.platform.descriptor.loader.json.QuarkusJsonPlatformDescriptorLoader b/independent-projects/tools/platform-descriptor-resolver-json/src/test/resources/META-INF/services/io.quarkus.platform.descriptor.loader.json.QuarkusJsonPlatformDescriptorLoader deleted file mode 100644 index 3698a45f9f4bdd..00000000000000 --- a/independent-projects/tools/platform-descriptor-resolver-json/src/test/resources/META-INF/services/io.quarkus.platform.descriptor.loader.json.QuarkusJsonPlatformDescriptorLoader +++ /dev/null @@ -1 +0,0 @@ -io.quarkus.platform.descriptor.resolver.json.test.TestJsonPlatformDescriptorLoader \ No newline at end of file diff --git a/independent-projects/tools/platform-descriptor-resolver-json/src/test/resources/quarkus-bom-descriptor/extensions.json b/independent-projects/tools/platform-descriptor-resolver-json/src/test/resources/quarkus-bom-descriptor/extensions.json deleted file mode 100644 index 309c411e5344bb..00000000000000 --- a/independent-projects/tools/platform-descriptor-resolver-json/src/test/resources/quarkus-bom-descriptor/extensions.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "bom": { - "groupId": "io.quarkus", - "artifactId": "quarkus-bom", - "version": "1.0.0.CR90" - }, - "quarkus-core-version": "1.0.0.CR90", - "extensions": [] -} \ No newline at end of file diff --git a/independent-projects/tools/platform-descriptor-resolver-json/src/test/resources/quarkus-bom/pom.xml b/independent-projects/tools/platform-descriptor-resolver-json/src/test/resources/quarkus-bom/pom.xml deleted file mode 100644 index caa7967f6ca081..00000000000000 --- a/independent-projects/tools/platform-descriptor-resolver-json/src/test/resources/quarkus-bom/pom.xml +++ /dev/null @@ -1,470 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-bom</artifactId> - <version>1.0.0.CR90</version> - <name>Quarkus - BOM</name> - <packaging>pom</packaging> - - <dependencyManagement> - <dependencies> - <!-- External BOMs --> - - <!-- Quarkus core --> - - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-core</artifactId> - <version>${project.version}</version> - </dependency> - <!-- - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-arc</artifactId> - <version>${project.version}</version> - </dependency> - - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-caffeine</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-jaxb</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-jackson</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-jsonb</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-jsonp</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-netty</artifactId> - <version>${project.version}</version> - </dependency> - - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-agroal</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-artemis-core</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-artemis-jms</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-elasticsearch-rest-client</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-security</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-elytron-security</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-elytron-security-properties-file</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-elytron-security-oauth2</artifactId> - <version>${project.version}</version> - </dependency> - - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-oidc</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-keycloak-authorization</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-flyway</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-hibernate-orm</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-panache-common</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-panacheql</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-hibernate-orm-panache</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-mongodb-panache</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-hibernate-search-orm-elasticsearch</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-hibernate-validator</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-infinispan-client</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-jaeger</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-jdbc-postgresql</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-jdbc-h2</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-jdbc-mariadb</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-jdbc-mssql</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-jdbc-mysql</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-jdbc-derby</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-kafka-client</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-kafka-streams</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-smallrye-health</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-smallrye-jwt</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-smallrye-context-propagation</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-smallrye-reactive-streams-operators</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-smallrye-reactive-type-converters</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-smallrye-reactive-messaging</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-smallrye-reactive-messaging-kafka</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-smallrye-reactive-messaging-amqp</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-smallrye-reactive-messaging-mqtt</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-smallrye-metrics</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-smallrye-openapi</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-smallrye-opentracing</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-rest-client</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-resteasy-common</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-resteasy</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-resteasy-jackson</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-resteasy-jsonb</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-resteasy-jaxb</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-resteasy-server-common</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-narayana-jta</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-undertow</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-smallrye-fault-tolerance</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-vertx-core</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-vertx</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-vertx-http</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-vertx-web</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-reactive-pg-client</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-reactive-mysql-client</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-mailer</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-mongodb-client</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-websockets</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-scheduler</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-quartz</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-spring-di</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-spring-web</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-spring-data-jpa</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-swagger-ui</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-kotlin</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-amazon-lambda</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-amazon-lambda-http</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-amazon-dynamodb</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-azure-functions-http</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-kubernetes</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-kubernetes-client</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-kogito</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-tika</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-neo4j</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-scala</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-jgit</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-narayana-stm</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-elytron-security-jdbc</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-vault</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-credentials</artifactId> - <version>${project.version}</version> - </dependency> ---> - </dependencies> - </dependencyManagement> -</project> diff --git a/independent-projects/tools/platform-descriptor-resolver-json/src/test/resources/quarkus.properties b/independent-projects/tools/platform-descriptor-resolver-json/src/test/resources/quarkus.properties deleted file mode 100644 index 9cb4e05a1c5bd2..00000000000000 --- a/independent-projects/tools/platform-descriptor-resolver-json/src/test/resources/quarkus.properties +++ /dev/null @@ -1 +0,0 @@ -quarkus-core-version = 1.0.0.CR90 \ No newline at end of file diff --git a/independent-projects/tools/pom.xml b/independent-projects/tools/pom.xml index c4f6ce3bb7b1a9..e080899b0aa83b 100644 --- a/independent-projects/tools/pom.xml +++ b/independent-projects/tools/pom.xml @@ -56,16 +56,26 @@ <smallrye-commons.version>1.5.0</smallrye-commons.version> </properties> <modules> - <module>platform-descriptor-api</module> + <module>artifact-api</module> + <module>registry-client</module> <module>message-writer</module> <module>devtools-testing</module> <module>codestarts</module> <module>devtools-common</module> <module>utilities</module> - <module>platform-descriptor-resolver-json</module> </modules> <dependencyManagement> <dependencies> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-devtools-artifact-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-devtools-registry-client</artifactId> + <version>${project.version}</version> + </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-compress</artifactId> @@ -106,16 +116,6 @@ <artifactId>quarkus-devtools-common</artifactId> <version>${project.version}</version> </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-platform-descriptor-api</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-platform-descriptor-resolver-json</artifactId> - <version>${project.version}</version> - </dependency> <dependency> <groupId>io.quarkus.http</groupId> <artifactId>quarkus-http-websockets-jsr</artifactId> diff --git a/independent-projects/tools/platform-descriptor-resolver-json/pom.xml b/independent-projects/tools/registry-client/pom.xml similarity index 61% rename from independent-projects/tools/platform-descriptor-resolver-json/pom.xml rename to independent-projects/tools/registry-client/pom.xml index b6362dcd8fb26a..dc14ba7c9fc0c2 100644 --- a/independent-projects/tools/platform-descriptor-resolver-json/pom.xml +++ b/independent-projects/tools/registry-client/pom.xml @@ -2,29 +2,37 @@ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> - <artifactId>quarkus-tools-parent</artifactId> <groupId>io.quarkus</groupId> + <artifactId>quarkus-tools-parent</artifactId> <version>999-SNAPSHOT</version> - <relativePath>../pom.xml</relativePath> </parent> - <modelVersion>4.0.0</modelVersion> - <artifactId>quarkus-platform-descriptor-resolver-json</artifactId> - <name>Quarkus - Dev tools - Platform JSON descriptor resolver</name> + <artifactId>quarkus-devtools-registry-client</artifactId> + <name>Quarkus - Dev tools - Registry Client API</name> <dependencies> <dependency> <groupId>io.quarkus</groupId> - <artifactId>quarkus-bootstrap-maven-resolver</artifactId> + <artifactId>quarkus-devtools-artifact-api</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> - <artifactId>quarkus-devtools-common</artifactId> + <artifactId>quarkus-devtools-message-writer</artifactId> </dependency> <dependency> - <groupId>org.jboss.logging</groupId> - <artifactId>jboss-logging</artifactId> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.dataformat</groupId> + <artifactId>jackson-dataformat-yaml</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-bootstrap-maven-resolver</artifactId> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> @@ -32,9 +40,8 @@ <scope>test</scope> </dependency> <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-bootstrap-core</artifactId> - <type>test-jar</type> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> <scope>test</scope> </dependency> </dependencies> diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/Constants.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/Constants.java new file mode 100644 index 00000000000000..a71dd7402442e7 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/Constants.java @@ -0,0 +1,21 @@ +package io.quarkus.registry; + +public interface Constants { + + String DEFAULT_REGISTRY_ID = "registry.quarkus.io"; + String DEFAULT_REGISTRY_GROUP_ID = "io.quarkus.registry"; + String DEFAULT_REGISTRY_ARTIFACT_VERSION = "1.0-SNAPSHOT"; + String DEFAULT_REGISTRY_DESCRIPTOR_ARTIFACT_ID = "quarkus-registry-descriptor"; + String DEFAULT_REGISTRY_NON_PLATFORM_EXTENSIONS_CATALOG_ARTIFACT_ID = "quarkus-non-platform-extensions"; + String DEFAULT_REGISTRY_PLATFORMS_CATALOG_ARTIFACT_ID = "quarkus-platforms"; + + String DEFAULT_REGISTRY_REST_URL = "https://registry.quarkus.io/api/1"; + String DEFAULT_REGISTRY_MAVEN_REPO_URL = "https://registry.quarkus.io/maven"; + String DEFAULT_REGISTRY_BACKUP_MAVEN_REPO_ID = "oss.sonatype.org"; + String DEFAULT_REGISTRY_BACKUP_MAVEN_REPO_URL = "https://oss.sonatype.org/content/repositories/snapshots"; + + String PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX = "-quarkus-platform-descriptor"; + String PLATFORM_PROPERTIES_ARTIFACT_ID_SUFFIX = "-quarkus-platform-properties"; + + String JSON = "json"; +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/ExclusiveProviderConflictException.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/ExclusiveProviderConflictException.java new file mode 100644 index 00000000000000..18ba96c10465e3 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/ExclusiveProviderConflictException.java @@ -0,0 +1,13 @@ +package io.quarkus.registry; + +import java.util.List; + +@SuppressWarnings("serial") +class ExclusiveProviderConflictException extends Exception { + + List<RegistryExtensionResolver> conflictingRegistries; + + ExclusiveProviderConflictException(List<RegistryExtensionResolver> conflictingRegistries) { + this.conflictingRegistries = conflictingRegistries; + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/ExtensionCatalogResolver.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/ExtensionCatalogResolver.java new file mode 100644 index 00000000000000..ff7a2d3288f2eb --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/ExtensionCatalogResolver.java @@ -0,0 +1,416 @@ +package io.quarkus.registry; + +import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; +import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; +import io.quarkus.devtools.messagewriter.MessageWriter; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.maven.ArtifactKey; +import io.quarkus.registry.catalog.ExtensionCatalog; +import io.quarkus.registry.catalog.Platform; +import io.quarkus.registry.catalog.PlatformCatalog; +import io.quarkus.registry.catalog.json.JsonCatalogMerger; +import io.quarkus.registry.catalog.json.JsonPlatformCatalog; +import io.quarkus.registry.client.RegistryClientFactory; +import io.quarkus.registry.client.maven.MavenRegistryClientFactory; +import io.quarkus.registry.config.RegistriesConfig; +import io.quarkus.registry.config.RegistriesConfigLocator; +import io.quarkus.registry.config.RegistryConfig; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; + +public class ExtensionCatalogResolver { + + public static Builder builder() { + return new ExtensionCatalogResolver().new Builder(); + } + + public class Builder { + + private MavenArtifactResolver artifactResolver; + private RegistriesConfig config; + private boolean built; + + private Builder() { + } + + public Builder artifactResolver(MavenArtifactResolver resolver) { + assertNotBuilt(); + artifactResolver = resolver; + return this; + } + + public Builder messageWriter(MessageWriter messageWriter) { + assertNotBuilt(); + log = messageWriter; + return this; + } + + public Builder config(RegistriesConfig registriesConfig) { + assertNotBuilt(); + config = registriesConfig; + return this; + } + + public ExtensionCatalogResolver build() { + assertNotBuilt(); + built = true; + completeConfig(); + buildRegistryClients(); + return ExtensionCatalogResolver.this; + } + + private void completeConfig() { + if (config == null) { + config = RegistriesConfigLocator.resolveConfig(); + } + if (log == null) { + log = config.isDebug() ? MessageWriter.debug() : MessageWriter.info(); + } + if (artifactResolver == null) { + try { + artifactResolver = MavenArtifactResolver.builder() + .setWorkspaceDiscovery(false) + .setArtifactTransferLogging(config.isDebug()) + .build(); + } catch (BootstrapMavenException e) { + throw new IllegalStateException("Failed to intialize the default Maven artifact resolver", e); + } + } + } + + private void buildRegistryClients() { + registries = new ArrayList<>(config.getRegistries().size()); + final RegistryClientFactory defaultClientFactory = new MavenRegistryClientFactory(artifactResolver, + log); + for (RegistryConfig config : config.getRegistries()) { + if (config.isDisabled()) { + continue; + } + try { + registries.add(new RegistryExtensionResolver(defaultClientFactory.buildRegistryClient(config), log)); + } catch (RegistryResolutionException e) { + log.warn(e.getMessage()); + continue; + } + } + } + + private void assertNotBuilt() { + if (built) { + throw new IllegalStateException("The builder has already built an instance"); + } + } + } + + private MessageWriter log; + private List<RegistryExtensionResolver> registries; + + public boolean hasRegistries() { + return !registries.isEmpty(); + } + + public PlatformCatalog resolvePlatformCatalog() throws RegistryResolutionException { + return resolvePlatformCatalog(null); + } + + public PlatformCatalog resolvePlatformCatalog(String quarkusVersion) throws RegistryResolutionException { + final Set<ArtifactKey> collectedPlatformKeys = new HashSet<>(); + + List<PlatformCatalog> catalogs = new ArrayList<>(registries.size()); + for (RegistryExtensionResolver qer : registries) { + final PlatformCatalog catalog = qer.resolvePlatformCatalog(quarkusVersion); + if (catalog != null) { + catalogs.add(catalog); + } + } + + if (catalogs.isEmpty()) { + return null; + } + if (catalogs.size() == 1) { + return catalogs.get(0); + } + + final JsonPlatformCatalog result = new JsonPlatformCatalog(); + + result.setDefaultPlatform(catalogs.get(0).getDefaultPlatform()); + + final List<Platform> collectedPlatforms = new ArrayList<>(); + result.setPlatforms(collectedPlatforms); + + collectedPlatformKeys.clear(); + for (PlatformCatalog c : catalogs) { + collectPlatforms(c, collectedPlatforms, collectedPlatformKeys); + } + + return result; + } + + private void collectPlatforms(PlatformCatalog catalog, List<Platform> collectedPlatforms, + Set<ArtifactKey> collectedPlatformKeys) { + for (Platform p : catalog.getPlatforms()) { + if (collectedPlatformKeys.add(p.getBom().getKey())) { + collectedPlatforms.add(p); + } + } + } + + public ExtensionCatalog resolveExtensionCatalog() throws RegistryResolutionException { + return resolveExtensionCatalog((String) null); + } + + public ExtensionCatalog resolveExtensionCatalog(String quarkusCoreVersion) throws RegistryResolutionException { + + final int registriesTotal = registries.size(); + if (registriesTotal == 0) { + throw new RegistryResolutionException("No registries configured"); + } + final Map<String, List<RegistryExtensionResolver>> registriesByQuarkusCore = new LinkedHashMap<>(registriesTotal); + List<ExtensionCatalog> extensionCatalogs = null; + + if (quarkusCoreVersion == null) { + // if there is only one registry and all the platforms it recommends are based + // on the same quarkus version then we don't need to execute extra requests to align the platforms + // on the common quarkus version + if (registriesTotal == 1) { + final PlatformCatalog platformsCatalog = registries.get(0).resolvePlatformCatalog(); + final List<Platform> platforms = platformsCatalog == null ? Collections.emptyList() + : platformsCatalog.getPlatforms(); + if (platforms.isEmpty()) { + // TODO this should be allowed + throw new RegistryResolutionException( + "Registry " + registries.get(0).getId() + " does not provide any platform"); + } + String commonQuarkusVersion = quarkusCoreVersion = platforms.get(0).getQuarkusCoreVersion(); + Platform defaultPlatform = null; + int i = 1; + while (i < platforms.size()) { + final Platform p = platforms.get(i++); + if (defaultPlatform == null && p.getBom().equals(platformsCatalog.getDefaultPlatform())) { + defaultPlatform = p; + quarkusCoreVersion = p.getQuarkusCoreVersion(); + } + if (commonQuarkusVersion != null && !commonQuarkusVersion.equals(p.getQuarkusCoreVersion())) { + commonQuarkusVersion = null; + } + } + if (commonQuarkusVersion != null) { + // all platforms are aligned on the same quarkus version + final RegistryExtensionResolver mainRegistry = registries.get(0); + registriesByQuarkusCore.put(commonQuarkusVersion, Arrays.asList(mainRegistry)); + extensionCatalogs = new ArrayList<>(); + i = 0; + while (i < platforms.size()) { + extensionCatalogs.add(mainRegistry.resolvePlatformExtensions(platforms.get(i++).getBom())); + } + } + } else { + quarkusCoreVersion = registries.get(0).resolveDefaultPlatform().getQuarkusCoreVersion(); + } + } + + if (extensionCatalogs == null) { + // collect all the platform extensions from all the registries compatible with the given quarkus core version + extensionCatalogs = new ArrayList<>(); + final Set<String> upstreamQuarkusVersions = new HashSet<>(1); + + collectPlatforms(quarkusCoreVersion, registriesByQuarkusCore, upstreamQuarkusVersions, extensionCatalogs); + + if (!upstreamQuarkusVersions.isEmpty()) { + Set<String> upstreamToProcess = upstreamQuarkusVersions; + Set<String> collectedUpstream = new HashSet<>(0); + do { + collectedUpstream.clear(); + final Iterator<String> upstreamIterator = upstreamToProcess.iterator(); + while (upstreamIterator.hasNext()) { + collectPlatforms(upstreamIterator.next(), + registriesByQuarkusCore, collectedUpstream, extensionCatalogs); + } + final Set<String> tmp = upstreamToProcess; + upstreamToProcess = collectedUpstream; + collectedUpstream = tmp; + } while (!upstreamToProcess.isEmpty()); + } + } + return appendNonPlatformExtensions(registriesByQuarkusCore, extensionCatalogs); + } + + public ExtensionCatalog resolveExtensionCatalog(List<ArtifactCoords> platforms) + throws RegistryResolutionException { + if (platforms.isEmpty()) { + return resolveExtensionCatalog(); + } + final List<ExtensionCatalog> catalogs = new ArrayList<>(platforms.size() + registries.size()); + Map<String, List<RegistryExtensionResolver>> registriesByQuarkusCore = new HashMap<>(2); + String quarkusVersion = null; + for (ArtifactCoords bom : platforms) { + final List<RegistryExtensionResolver> registries; + try { + registries = filterRegistries(r -> r.checkPlatform(bom)); + } catch (ExclusiveProviderConflictException e) { + final StringBuilder buf = new StringBuilder(); + buf.append( + "The following registries were configured as exclusive providers of the "); + buf.append(bom); + buf.append("platform: ").append(e.conflictingRegistries.get(0).getId()); + for (int i = 1; i < e.conflictingRegistries.size(); ++i) { + buf.append(", ").append(e.conflictingRegistries.get(i).getId()); + } + throw new RuntimeException(buf.toString()); + } + + final ExtensionCatalog catalog = resolvePlatformExtensions(bom, registries); + if (catalog != null) { + catalogs.add(catalog); + if (quarkusVersion == null) { + quarkusVersion = catalog.getQuarkusCoreVersion(); + registriesByQuarkusCore.put(quarkusVersion, getRegistriesForQuarkusVersion(quarkusVersion)); + } + final String upstreamQuarkusVersion = catalog.getUpstreamQuarkusCoreVersion(); + if (upstreamQuarkusVersion != null && !registriesByQuarkusCore.containsKey(upstreamQuarkusVersion)) { + registriesByQuarkusCore.put(upstreamQuarkusVersion, + getRegistriesForQuarkusVersion(upstreamQuarkusVersion)); + } + } + } + return appendNonPlatformExtensions(registriesByQuarkusCore, catalogs); + } + + private ExtensionCatalog resolvePlatformExtensions(ArtifactCoords bom, List<RegistryExtensionResolver> registries) { + if (registries.isEmpty()) { + log.debug("None of the configured registries recognizes platform %s", bom); + return null; + } + for (RegistryExtensionResolver registry : registries) { + try { + return registry.resolvePlatformExtensions(bom); + } catch (RegistryResolutionException e) { + } + } + final StringBuilder buf = new StringBuilder(); + buf.append("Failed to resolve platform ").append(bom).append(" using the following registries: "); + buf.append(registries.get(0).getId()); + for (int i = 1; i < registries.size(); ++i) { + buf.append(", ").append(registries.get(i++)); + } + log.warn(buf.toString()); + return null; + } + + private ExtensionCatalog appendNonPlatformExtensions( + final Map<String, List<RegistryExtensionResolver>> registriesByQuarkusCore, + List<ExtensionCatalog> extensionCatalogs) throws RegistryResolutionException { + for (Map.Entry<String, List<RegistryExtensionResolver>> quarkusVersionRegistries : registriesByQuarkusCore.entrySet()) { + for (RegistryExtensionResolver registry : quarkusVersionRegistries.getValue()) { + final ExtensionCatalog nonPlatformCatalog = registry + .resolveNonPlatformExtensions(quarkusVersionRegistries.getKey()); + if (nonPlatformCatalog != null) { + extensionCatalogs.add(nonPlatformCatalog); + } + } + } + return JsonCatalogMerger.merge(extensionCatalogs); + } + + private void collectPlatforms(String quarkusCoreVersion, + Map<String, List<RegistryExtensionResolver>> registriesByQuarkusCore, + Set<String> upstreamQuarkusVersions, List<ExtensionCatalog> extensionCatalogs) throws RegistryResolutionException { + List<RegistryExtensionResolver> quarkusVersionRegistries = registriesByQuarkusCore.get(quarkusCoreVersion); + if (quarkusVersionRegistries != null) { + return; + } + + quarkusVersionRegistries = getRegistriesForQuarkusVersion(quarkusCoreVersion); + registriesByQuarkusCore.put(quarkusCoreVersion, quarkusVersionRegistries); + + for (RegistryExtensionResolver registry : quarkusVersionRegistries) { + final PlatformCatalog platformCatalog = registry.resolvePlatformCatalog(quarkusCoreVersion); + if (platformCatalog == null) { + continue; + } + final List<Platform> platforms = platformCatalog.getPlatforms(); + if (platforms.isEmpty()) { + continue; + } + for (Platform p : platforms) { + final String upstreamQuarkusCoreVersion = p.getUpstreamQuarkusCoreVersion(); + if (upstreamQuarkusCoreVersion != null + && !registriesByQuarkusCore.containsKey(upstreamQuarkusCoreVersion)) { + upstreamQuarkusVersions.add(upstreamQuarkusCoreVersion); + } + final ExtensionCatalog catalog = registry.resolvePlatformExtensions(p.getBom()); + if (catalog != null) { + extensionCatalogs.add(catalog); + } + } + } + } + + private List<RegistryExtensionResolver> getRegistriesForQuarkusVersion(String quarkusCoreVersion) { + try { + return filterRegistries(r -> r.checkQuarkusVersion(quarkusCoreVersion)); + } catch (ExclusiveProviderConflictException e) { + final StringBuilder buf = new StringBuilder(); + buf.append( + "The following registries were configured as exclusive providers of extensions based on Quarkus version "); + buf.append(quarkusCoreVersion); + buf.append(": ").append(e.conflictingRegistries.get(0).getId()); + for (int i = 1; i < e.conflictingRegistries.size(); ++i) { + buf.append(", ").append(e.conflictingRegistries.get(i).getId()); + } + throw new RuntimeException(buf.toString()); + } + } + + private List<RegistryExtensionResolver> filterRegistries(Function<RegistryExtensionResolver, Integer> recognizer) + throws ExclusiveProviderConflictException { + RegistryExtensionResolver exclusiveProvider = null; + List<RegistryExtensionResolver> filtered = null; + List<RegistryExtensionResolver> conflicts = null; + for (int i = 0; i < registries.size(); ++i) { + final RegistryExtensionResolver registry = registries.get(i); + final int versionCheck = recognizer.apply(registry); + + if (versionCheck == RegistryExtensionResolver.VERSION_NOT_RECOGNIZED) { + if (exclusiveProvider == null && filtered == null) { + filtered = new ArrayList<>(registries.size() - 1); + for (int j = 0; j < i; ++j) { + filtered.add(registries.get(j)); + } + } + continue; + } + + if (versionCheck == RegistryExtensionResolver.VERSION_EXCLUSIVE_PROVIDER) { + if (exclusiveProvider == null) { + exclusiveProvider = registry; + } else { + if (conflicts == null) { + conflicts = new ArrayList<>(); + conflicts.add(exclusiveProvider); + } + conflicts.add(registry); + } + } + + if (filtered != null) { + filtered.add(registry); + } + } + + if (conflicts != null) { + throw new ExclusiveProviderConflictException(conflicts); + } + + return exclusiveProvider == null ? filtered == null ? registries : filtered : Arrays.asList(exclusiveProvider); + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/RegistryExtensionResolver.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/RegistryExtensionResolver.java new file mode 100644 index 00000000000000..6727b1b08f45f3 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/RegistryExtensionResolver.java @@ -0,0 +1,92 @@ +package io.quarkus.registry; + +import io.quarkus.devtools.messagewriter.MessageWriter; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.catalog.ExtensionCatalog; +import io.quarkus.registry.catalog.Platform; +import io.quarkus.registry.catalog.PlatformCatalog; +import io.quarkus.registry.client.RegistryClient; +import io.quarkus.registry.config.RegistryConfig; +import io.quarkus.registry.util.GlobUtil; +import java.util.Iterator; +import java.util.Objects; +import java.util.regex.Pattern; + +class RegistryExtensionResolver { + + public static final int VERSION_NOT_RECOGNIZED = -1; + public static final int VERSION_NOT_CONFIGURED = 0; + public static final int VERSION_RECOGNIZED = 1; + public static final int VERSION_EXCLUSIVE_PROVIDER = 2; + + private final RegistryConfig config; + private final RegistryClient extensionResolver; + + private Pattern recognizedQuarkusVersions; + + RegistryExtensionResolver(RegistryClient extensionResolver, + MessageWriter log) throws RegistryResolutionException { + this.extensionResolver = Objects.requireNonNull(extensionResolver, "Registry extension resolver is null"); + this.config = extensionResolver.resolveRegistryConfig(); + + String versionExpr = config.getQuarkusVersions() == null ? null + : config.getQuarkusVersions().getRecognizedVersionsExpression(); + if (versionExpr != null) { + recognizedQuarkusVersions = Pattern.compile(GlobUtil.toRegexPattern(versionExpr)); + } + } + + String getId() { + return config.getId(); + } + + int checkQuarkusVersion(String quarkusVersion) { + if (recognizedQuarkusVersions == null) { + return VERSION_NOT_CONFIGURED; + } + if (!recognizedQuarkusVersions.matcher(quarkusVersion).matches()) { + return VERSION_NOT_RECOGNIZED; + } + return config.getQuarkusVersions().isExclusiveProvider() ? VERSION_EXCLUSIVE_PROVIDER + : VERSION_RECOGNIZED; + } + + int checkPlatform(ArtifactCoords platform) { + // TODO this should be allowed to check the full coordinates + return checkQuarkusVersion(platform.getVersion()); + } + + PlatformCatalog resolvePlatformCatalog() throws RegistryResolutionException { + return resolvePlatformCatalog(null); + } + + PlatformCatalog resolvePlatformCatalog(String quarkusCoreVersion) throws RegistryResolutionException { + return extensionResolver.resolvePlatforms(quarkusCoreVersion); + } + + Platform resolveDefaultPlatform() throws RegistryResolutionException { + final PlatformCatalog platformsCatalog = resolvePlatformCatalog(); + final ArtifactCoords defaultCoords = platformsCatalog.getDefaultPlatform(); + for (Platform p : platformsCatalog.getPlatforms()) { + if (defaultCoords.equals(p.getBom())) { + return p; + } + } + final StringBuilder buf = new StringBuilder(); + buf.append("Failed to locate the default platform ").append(defaultCoords).append(" in the catalog of "); + final Iterator<Platform> i = platformsCatalog.getPlatforms().iterator(); + buf.append(i.next().getBom()); + while (i.hasNext()) { + buf.append(", ").append(i.next().getBom()); + } + throw new RegistryResolutionException(buf.toString()); + } + + ExtensionCatalog resolveNonPlatformExtensions(String quarkusCoreVersion) throws RegistryResolutionException { + return extensionResolver.resolveNonPlatformExtensions(quarkusCoreVersion); + } + + ExtensionCatalog resolvePlatformExtensions(ArtifactCoords platform) throws RegistryResolutionException { + return extensionResolver.resolvePlatformExtensions(platform); + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/RegistryResolutionException.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/RegistryResolutionException.java new file mode 100644 index 00000000000000..468c93dbdbdd91 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/RegistryResolutionException.java @@ -0,0 +1,12 @@ +package io.quarkus.registry; + +public class RegistryResolutionException extends Exception { + + public RegistryResolutionException(String message, Throwable cause) { + super(message, cause); + } + + public RegistryResolutionException(String message) { + super(message); + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/Category.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/Category.java new file mode 100644 index 00000000000000..35f9b066a28e49 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/Category.java @@ -0,0 +1,14 @@ +package io.quarkus.registry.catalog; + +import java.util.Map; + +public interface Category { + + String getId(); + + String getName(); + + String getDescription(); + + Map<String, Object> getMetadata(); +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/Extension.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/Extension.java new file mode 100644 index 00000000000000..8c2b552eff2566 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/Extension.java @@ -0,0 +1,102 @@ +package io.quarkus.registry.catalog; + +import io.quarkus.maven.ArtifactCoords; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public interface Extension { + + String MD_SHORT_NAME = "short-name"; + String MD_CODESTART = "codestart"; + String MD_GUIDE = "guide"; + /** Key used for keywords in metadata **/ + String MD_KEYWORDS = "keywords"; + String MD_UNLISTED = "unlisted"; + String MD_STATUS = "status"; + + String getName(); + + String getDescription(); + + ArtifactCoords getArtifact(); + + List<ExtensionOrigin> getOrigins(); + + default boolean hasPlatformOrigin() { + final List<ExtensionOrigin> origins = getOrigins(); + if (origins == null || origins.isEmpty()) { + return false; + } + for (ExtensionOrigin o : origins) { + if (o.isPlatform()) { + return true; + } + } + return false; + } + + Map<String, Object> getMetadata(); + + @SuppressWarnings("unchecked") + default List<String> getKeywords() { + List<String> kw = (List<String>) getMetadata().get(MD_KEYWORDS); + return kw == null ? Collections.emptyList() : kw; + } + + /** + * List of strings to use for matching. + * + * Returns keywords + artifactid all in lowercase. + * + * @return list of labels to use for matching. + */ + default List<String> labelsForMatching() { + final List<String> keywords = getKeywords(); + final List<String> list = new ArrayList<>(1 + (keywords == null ? 0 : keywords.size())); + if (keywords != null) { + list.addAll(keywords.stream().map(String::toLowerCase).collect(Collectors.toList())); + } + list.add(getArtifact().getArtifactId().toLowerCase()); + return list; + } + + /** + * + * @return string representing the location of primary guide for this extension. + */ + default String getGuide() { + return (String) getMetadata().get(MD_GUIDE); + } + + default String managementKey() { + final ArtifactCoords artifact = getArtifact(); + return artifact.getGroupId() + ":" + artifact.getArtifactId(); + } + + default String getShortName() { + final String shortName = (String) getMetadata().get(MD_SHORT_NAME); + return shortName == null ? getName() : shortName; + } + + default String getCodestart() { + return (String) getMetadata().get(MD_CODESTART); + } + + default boolean isUnlisted() { + final Object val = getMetadata().get(MD_UNLISTED); + if (val == null) { + return false; + } + if (val instanceof Boolean) { + return (Boolean) val; + } + if (val instanceof String) { + return Boolean.parseBoolean((String) val); + } + return false; + } + +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/ExtensionCatalog.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/ExtensionCatalog.java new file mode 100644 index 00000000000000..0561aae31dd12d --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/ExtensionCatalog.java @@ -0,0 +1,58 @@ +package io.quarkus.registry.catalog; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +public interface ExtensionCatalog extends ExtensionOrigin { + + /** + * All the origins this catalog is derived from. + * + * @return all the origins this catalog derives from. + */ + List<ExtensionOrigin> getDerivedFrom(); + + /** + * Quarkus core version used by the extensions in this catalog. + * + * @return Quarkus core version used by the extensions in this catalog + */ + String getQuarkusCoreVersion(); + + /** + * In case the catalog was built for a custom version of the Quarkus core, + * this version represents the corresponding upstream community Quarkus core version. + * This is done to be able to link the custom builds of Quarkus back to the upstream community + * extensions ecosystem. + * + * This method may return null in case the corresponding version does not exist in the upstream community + * or simply to link back to it. + * + * + * @return the upstream community Quarkus core version corresponding to the Quarkus core version + * used in this catalog + */ + String getUpstreamQuarkusCoreVersion(); + + /** + * Quarkus extensions that constitute the catalog. + * + * @return Quarkus extensions that constitute the catalog. + */ + Collection<Extension> getExtensions(); + + /** + * Extension categories + * + * @return extension categories + */ + List<Category> getCategories(); + + /** + * Various metadata attached to the catalog + * + * @return metadata attached to the catalog + */ + Map<String, Object> getMetadata(); +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/ExtensionOrigin.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/ExtensionOrigin.java new file mode 100644 index 00000000000000..4380b6bf6046af --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/ExtensionOrigin.java @@ -0,0 +1,31 @@ +package io.quarkus.registry.catalog; + +import io.quarkus.maven.ArtifactCoords; + +public interface ExtensionOrigin { + + /** + * Origin ID. E.g. GAV of the descriptor. + * + * @return origin ID + */ + String getId(); + + /** + * BOM that should be imported by a project + * using extensions from this origin. This method normally won't return null. + * Given that any Quarkus project would typically be importing at least some version of + * io.quarkus:quarkus-bom even if extensions used in the project aren't managed by the quarkus-bom/ + * the project + * + * @return BOM coordinates + */ + ArtifactCoords getBom(); + + /** + * Whether the origin represents a platform. + * + * @return true in case the origin is a platform, otherwise - false + */ + boolean isPlatform(); +} diff --git a/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/dependencies/ExtensionPredicate.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/ExtensionPredicate.java similarity index 94% rename from independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/dependencies/ExtensionPredicate.java rename to independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/ExtensionPredicate.java index 6655a1de710cce..756d30aabcc450 100644 --- a/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/dependencies/ExtensionPredicate.java +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/ExtensionPredicate.java @@ -1,4 +1,4 @@ -package io.quarkus.dependencies; +package io.quarkus.registry.catalog; import java.util.List; import java.util.Objects; @@ -62,7 +62,7 @@ public boolean test(Extension extension) { } // Partial matches on name, artifactId and short names if (extensionName.toLowerCase().contains(q) - || extension.getArtifactId().toLowerCase().contains(q) + || extension.getArtifact().getArtifactId().toLowerCase().contains(q) || shortName.toLowerCase().contains(q)) { return true; } @@ -73,7 +73,7 @@ public boolean test(Extension extension) { // find by pattern Pattern pattern = toRegex(q); return pattern != null && (pattern.matcher(extensionName.toLowerCase()).matches() - || pattern.matcher(extension.getArtifactId().toLowerCase()).matches() + || pattern.matcher(extension.getArtifact().getArtifactId().toLowerCase()).matches() || pattern.matcher(shortName.toLowerCase()).matches() || matchLabels(pattern, extension.getKeywords())); } @@ -82,7 +82,7 @@ public boolean isExactMatch(Extension extension) { String extensionName = Objects.toString(extension.getName(), ""); // Try exact matches if (extensionName.equalsIgnoreCase(q) || - matchesArtifactId(extension.getArtifactId(), q)) { + matchesArtifactId(extension.getArtifact().getArtifactId(), q)) { return true; } return false; diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/Platform.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/Platform.java new file mode 100644 index 00000000000000..99ade7d77a3649 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/Platform.java @@ -0,0 +1,12 @@ +package io.quarkus.registry.catalog; + +import io.quarkus.maven.ArtifactCoords; + +public interface Platform { + + ArtifactCoords getBom(); + + String getQuarkusCoreVersion(); + + String getUpstreamQuarkusCoreVersion(); +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/PlatformCatalog.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/PlatformCatalog.java new file mode 100644 index 00000000000000..30954d3da4dbf7 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/PlatformCatalog.java @@ -0,0 +1,11 @@ +package io.quarkus.registry.catalog; + +import io.quarkus.maven.ArtifactCoords; +import java.util.List; + +public interface PlatformCatalog { + + List<Platform> getPlatforms(); + + ArtifactCoords getDefaultPlatform(); +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonArtifactCoordsDeserializer.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonArtifactCoordsDeserializer.java new file mode 100644 index 00000000000000..149ed84afd241e --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonArtifactCoordsDeserializer.java @@ -0,0 +1,17 @@ +package io.quarkus.registry.catalog.json; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import io.quarkus.maven.ArtifactCoords; +import java.io.IOException; + +public class JsonArtifactCoordsDeserializer extends JsonDeserializer<ArtifactCoords> { + + @Override + public ArtifactCoords deserialize(JsonParser p, DeserializationContext ctxt) + throws IOException, JsonProcessingException { + return ArtifactCoords.fromString(p.getText()); + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonArtifactCoordsMixin.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonArtifactCoordsMixin.java new file mode 100644 index 00000000000000..3095c2143e86c7 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonArtifactCoordsMixin.java @@ -0,0 +1,14 @@ +package io.quarkus.registry.catalog.json; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.quarkus.maven.ArtifactKey; + +@JsonSerialize(using = JsonArtifactCoordsSerializer.class) +@JsonDeserialize(using = JsonArtifactCoordsDeserializer.class) +public interface JsonArtifactCoordsMixin { + + @JsonIgnore + ArtifactKey getKey(); +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonArtifactCoordsSerializer.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonArtifactCoordsSerializer.java new file mode 100644 index 00000000000000..94a6c6e521ffe2 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonArtifactCoordsSerializer.java @@ -0,0 +1,15 @@ +package io.quarkus.registry.catalog.json; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import io.quarkus.maven.ArtifactCoords; +import java.io.IOException; + +public class JsonArtifactCoordsSerializer extends JsonSerializer<ArtifactCoords> { + + @Override + public void serialize(ArtifactCoords value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeString(value.toString()); + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonCatalogMapperHelper.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonCatalogMapperHelper.java new file mode 100644 index 00000000000000..b6af65ad76cc32 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonCatalogMapperHelper.java @@ -0,0 +1,64 @@ +package io.quarkus.registry.catalog.json; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.SerializationFeature; +import io.quarkus.maven.ArtifactCoords; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; + +public class JsonCatalogMapperHelper { + + private static ObjectMapper mapper; + + public static ObjectMapper mapper() { + return mapper == null ? mapper = initMapper(new ObjectMapper()) : mapper; + } + + public static ObjectMapper initMapper(ObjectMapper mapper) { + mapper.addMixIn(ArtifactCoords.class, JsonArtifactCoordsMixin.class); + mapper.enable(SerializationFeature.INDENT_OUTPUT); + mapper.enable(JsonParser.Feature.ALLOW_COMMENTS); + mapper.setPropertyNamingStrategy(PropertyNamingStrategies.KEBAB_CASE); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + return mapper; + } + + public static void serialize(Object catalog, Path p) throws IOException { + if (!Files.exists(p.getParent())) { + Files.createDirectories(p.getParent()); + } + try (BufferedWriter writer = Files.newBufferedWriter(p)) { + serialize(catalog, writer); + } + } + + public static void serialize(Object catalog, Writer writer) throws IOException { + mapper().writeValue(writer, catalog); + } + + public static <T> T deserialize(Path p, Class<T> t) throws IOException { + if (!Files.exists(p)) { + throw new IllegalArgumentException("File " + p + " does not exist"); + } + try (BufferedReader reader = Files.newBufferedReader(p)) { + return mapper().readValue(reader, t); + } + } + + public static <T> T deserialize(InputStream is, Class<T> t) throws IOException { + return mapper().readValue(is, t); + } + + public static <T> T deserialize(Reader reader, Class<T> t) throws IOException { + return mapper().readValue(reader, t); + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonCatalogMerger.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonCatalogMerger.java new file mode 100644 index 00000000000000..435a821accb828 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonCatalogMerger.java @@ -0,0 +1,85 @@ +package io.quarkus.registry.catalog.json; + +import io.quarkus.maven.ArtifactKey; +import io.quarkus.registry.catalog.Category; +import io.quarkus.registry.catalog.Extension; +import io.quarkus.registry.catalog.ExtensionCatalog; +import io.quarkus.registry.catalog.ExtensionOrigin; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class JsonCatalogMerger { + + public static ExtensionCatalog merge(List<ExtensionCatalog> catalogs) { + + if (catalogs.isEmpty()) { + throw new IllegalArgumentException("No catalogs provided"); + } + if (catalogs.size() == 1) { + return catalogs.get(0); + } + + final List<ExtensionCatalog> roots = detectRoots(catalogs); + if (roots.size() == 1) { + return roots.get(0); + } + + final JsonExtensionCatalog combined = new JsonExtensionCatalog(); + + final Map<String, Category> categories = new LinkedHashMap<>(); + final Map<String, ExtensionOrigin> derivedFrom = new LinkedHashMap<>(); + final Map<ArtifactKey, Extension> extensions = new LinkedHashMap<>(); + final Map<String, Object> metadata = new HashMap<>(); + for (ExtensionCatalog catalog : roots) { + if (combined.getBom() == null) { + combined.setBom(catalog.getBom()); + } + + if (catalog.getId() != null) { + derivedFrom.putIfAbsent(catalog.getId(), catalog); + } + catalog.getDerivedFrom().forEach(o -> derivedFrom.putIfAbsent(o.getId(), o)); + + catalog.getCategories().forEach(c -> categories.putIfAbsent(c.getId(), c)); + catalog.getExtensions().forEach(e -> extensions.putIfAbsent(e.getArtifact().getKey(), e)); + catalog.getMetadata().entrySet().forEach(entry -> metadata.putIfAbsent(entry.getKey(), entry.getValue())); + + if (combined.getQuarkusCoreVersion() == null && catalog.getQuarkusCoreVersion() != null) { + combined.setQuarkusCoreVersion(catalog.getQuarkusCoreVersion()); + } + if (combined.getUpstreamQuarkusCoreVersion() == null && catalog.getUpstreamQuarkusCoreVersion() != null + && !combined.getQuarkusCoreVersion().equals(catalog.getUpstreamQuarkusCoreVersion())) { + combined.setUpstreamQuarkusCoreVersion(catalog.getUpstreamQuarkusCoreVersion()); + } + } + + combined.setCategories(new ArrayList<>(categories.values())); + combined.setDerivedFrom(new ArrayList<>(derivedFrom.values())); + combined.setExtensions(new ArrayList<>(extensions.values())); + combined.setMetadata(metadata); + return combined; + } + + private static List<ExtensionCatalog> detectRoots(List<ExtensionCatalog> catalogs) { + final Set<String> allDerivedFrom = new HashSet<>(catalogs.size()); + for (ExtensionCatalog catalog : catalogs) { + for (ExtensionOrigin o : catalog.getDerivedFrom()) { + allDerivedFrom.add(o.getId()); + } + } + final List<ExtensionCatalog> roots = new ArrayList<>(catalogs.size()); + for (ExtensionCatalog catalog : catalogs) { + if (catalog.getId() == null) { + roots.add(catalog); + } else if (!allDerivedFrom.contains(catalog.getId())) { + roots.add(catalog); + } + } + return roots; + } +} diff --git a/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/dependencies/Category.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonCategory.java similarity index 67% rename from independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/dependencies/Category.java rename to independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonCategory.java index 55c57769900057..fdf8df61698a6f 100644 --- a/independent-projects/tools/platform-descriptor-api/src/main/java/io/quarkus/dependencies/Category.java +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonCategory.java @@ -1,19 +1,20 @@ -package io.quarkus.dependencies; +package io.quarkus.registry.catalog.json; -import java.io.Serializable; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.quarkus.registry.catalog.Category; import java.util.Map; import java.util.Objects; -public class Category implements Serializable { +@JsonInclude(JsonInclude.Include.NON_NULL) +public class JsonCategory implements Category { - public static final String MD_PINNED = "pinned"; + protected String id; + protected String name; + protected String description; - String id; - String name; - String description; - - Map<String, Object> metadata; + protected Map<String, Object> metadata; + @Override public String getId() { return id; } @@ -22,6 +23,7 @@ public void setId(String id) { this.id = id; } + @Override public String getName() { return name; } @@ -30,6 +32,7 @@ public void setName(String name) { this.name = name; } + @Override public String getDescription() { return description; } @@ -38,6 +41,7 @@ public void setDescription(String description) { this.description = description; } + @Override public Map<String, Object> getMetadata() { return metadata; } @@ -54,7 +58,7 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) { return false; } - Category category = (Category) o; + final JsonCategory category = (JsonCategory) o; return Objects.equals(id, category.id); } diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonExtension.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonExtension.java new file mode 100644 index 00000000000000..4b43b2c1473d0a --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonExtension.java @@ -0,0 +1,153 @@ +package io.quarkus.registry.catalog.json; + +import com.fasterxml.jackson.annotation.JsonIdentityReference; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.catalog.Extension; +import io.quarkus.registry.catalog.ExtensionOrigin; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class JsonExtension implements Extension { + + private String name; + private String description; + private Map<String, Object> metadata; + private ArtifactCoords artifact; + private List<ExtensionOrigin> origins; + + // to support legacy format + private String groupId; + private String artifactId; + private String version; + + public void setGroupId(String groupId) { + this.groupId = groupId; + } + + public void setArtifactId(String artifactId) { + this.artifactId = artifactId; + } + + public void setVersion(String version) { + this.version = version; + } + + @Override + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public ArtifactCoords getArtifact() { + if (artifact == null && artifactId != null) { + artifact = new ArtifactCoords(groupId, artifactId, version); + } + return artifact; + } + + public void setArtifact(ArtifactCoords coords) { + this.artifact = coords; + } + + public void setOrigins(List<ExtensionOrigin> origins) { + this.origins = origins; + } + + @Override + @JsonIdentityReference(alwaysAsId = true) + @JsonDeserialize(contentAs = JsonExtensionOrigin.class) + public List<ExtensionOrigin> getOrigins() { + return origins == null ? Collections.emptyList() : origins; + } + + @Override + public Map<String, Object> getMetadata() { + return metadata == null ? metadata = new HashMap<>() : metadata; + } + + public void setMetadata(Map<String, Object> metadata) { + this.metadata = metadata; + } + + @JsonIgnore + public Extension setKeywords(List<String> keywords) { + getMetadata().put(MD_KEYWORDS, keywords); + return this; + } + + @JsonIgnore + public Extension setGuide(String guide) { + getMetadata().put(MD_GUIDE, guide); + return this; + } + + @JsonIgnore + public Extension setShortName(String shortName) { + getMetadata().put(MD_SHORT_NAME, shortName); + return this; + } + + @JsonIgnore + public Extension setCodestart(String codestart) { + getMetadata().put(MD_CODESTART, codestart); + return this; + } + + @JsonIgnore + public void setUnlisted(boolean unlisted) { + getMetadata().put(MD_UNLISTED, unlisted); + } + + public Extension addMetadata(String key, Object value) { + getMetadata().put(key, value); + return this; + + } + + public Extension removeMetadata(String key) { + getMetadata().remove(key); + return this; + } + + @Override + public String toString() { + return name + " " + getArtifact(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + JsonExtension extension = (JsonExtension) o; + return Objects.equals(artifact, extension.artifact); + } + + @Override + public int hashCode() { + return Objects.hash(artifact); + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonExtensionCatalog.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonExtensionCatalog.java new file mode 100644 index 00000000000000..c1dcbb60597c05 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonExtensionCatalog.java @@ -0,0 +1,87 @@ +package io.quarkus.registry.catalog.json; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import io.quarkus.registry.catalog.Category; +import io.quarkus.registry.catalog.Extension; +import io.quarkus.registry.catalog.ExtensionCatalog; +import io.quarkus.registry.catalog.ExtensionOrigin; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class JsonExtensionCatalog extends JsonExtensionOrigin implements ExtensionCatalog { + + private String quarkusCore; + private String upstreamQuarkusCore; + private List<ExtensionOrigin> derivedFrom; + private List<Extension> extensions; + private List<Category> categories; + private Map<String, Object> metadata; + + @Override + public String getQuarkusCoreVersion() { + return quarkusCore; + } + + public void setQuarkusCoreVersion(String quarkusCore) { + this.quarkusCore = quarkusCore; + } + + @Override + public String getUpstreamQuarkusCoreVersion() { + return upstreamQuarkusCore; + } + + public void setUpstreamQuarkusCoreVersion(String upstreamQuarkusCore) { + this.upstreamQuarkusCore = upstreamQuarkusCore; + } + + @Override + @JsonDeserialize(contentAs = JsonExtensionOrigin.class) + public List<ExtensionOrigin> getDerivedFrom() { + return derivedFrom == null ? Collections.emptyList() : derivedFrom; + } + + public void setDerivedFrom(List<ExtensionOrigin> origins) { + this.derivedFrom = origins; + } + + @Override + @JsonDeserialize(contentAs = JsonExtension.class) + public List<Extension> getExtensions() { + return extensions == null ? Collections.emptyList() : extensions; + } + + public void setExtensions(List<Extension> extensions) { + this.extensions = extensions; + } + + public void addExtension(Extension e) { + if (extensions == null) { + extensions = new ArrayList<>(); + } + extensions.add(e); + } + + @Override + @JsonDeserialize(contentAs = JsonCategory.class) + public List<Category> getCategories() { + return categories == null ? Collections.emptyList() : categories; + } + + public void setCategories(List<Category> categories) { + this.categories = categories; + } + + @Override + public Map<String, Object> getMetadata() { + return metadata == null ? Collections.emptyMap() : metadata; + } + + public void setMetadata(Map<String, Object> metadata) { + this.metadata = metadata; + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonExtensionOrigin.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonExtensionOrigin.java new file mode 100644 index 00000000000000..71abbe826258d1 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonExtensionOrigin.java @@ -0,0 +1,53 @@ +package io.quarkus.registry.catalog.json; + +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.catalog.ExtensionOrigin; + +@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") +public class JsonExtensionOrigin implements ExtensionOrigin { + + protected String id; + protected boolean platform; + protected ArtifactCoords bom; + + @Override + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + public ArtifactCoords getBom() { + return bom; + } + + public void setBom(ArtifactCoords bom) { + this.bom = bom; + } + + @Override + public boolean isPlatform() { + return platform; + } + + public void setPlatform(boolean platform) { + this.platform = platform; + } + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder(); + buf.append('['); + if (id != null) { + buf.append("id=").append(id).append(' '); + } + buf.append("platform=").append(platform); + buf.append(" boms=").append(bom); + return buf.append(']').toString(); + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonPlatform.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonPlatform.java new file mode 100644 index 00000000000000..ba29ca4e5eb047 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonPlatform.java @@ -0,0 +1,52 @@ +package io.quarkus.registry.catalog.json; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.catalog.Platform; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class JsonPlatform implements Platform { + + public static JsonPlatform of(ArtifactCoords bom) { + JsonPlatform p = new JsonPlatform(); + p.setBom(Objects.requireNonNull(bom, "bom can't be null")); + return p; + } + + private ArtifactCoords bom; + private String quarkusCore; + private String upstreamQuarkusCore; + + @Override + public ArtifactCoords getBom() { + return bom; + } + + public void setBom(ArtifactCoords bom) { + this.bom = bom; + } + + @Override + public String getQuarkusCoreVersion() { + return quarkusCore; + } + + public void setQuarkusCoreVersion(String quarkusCore) { + this.quarkusCore = quarkusCore; + } + + @Override + public String getUpstreamQuarkusCoreVersion() { + return upstreamQuarkusCore; + } + + public void setUpstreamQuarkusCoreVersion(String upstreamQuarkusCore) { + this.upstreamQuarkusCore = upstreamQuarkusCore; + } + + @Override + public String toString() { + return "[platform " + bom + ", quarkus-core=" + quarkusCore + ", upstream-quarkus-core=" + upstreamQuarkusCore + "]"; + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonPlatformCatalog.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonPlatformCatalog.java new file mode 100644 index 00000000000000..988993193c5155 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/catalog/json/JsonPlatformCatalog.java @@ -0,0 +1,43 @@ +package io.quarkus.registry.catalog.json; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.catalog.Platform; +import io.quarkus.registry.catalog.PlatformCatalog; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class JsonPlatformCatalog implements PlatformCatalog { + + private List<Platform> platforms; + private ArtifactCoords defaultPlatform; + + @Override + @JsonDeserialize(contentAs = JsonPlatform.class) + public List<Platform> getPlatforms() { + return platforms == null ? Collections.emptyList() : platforms; + } + + public void setPlatforms(List<Platform> platforms) { + this.platforms = platforms; + } + + public void addPlatform(Platform platform) { + if (platforms == null) { + platforms = new ArrayList<>(); + } + platforms.add(platform); + } + + @Override + public ArtifactCoords getDefaultPlatform() { + return defaultPlatform; + } + + public void setDefaultPlatform(ArtifactCoords defaultPlatform) { + this.defaultPlatform = defaultPlatform; + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/RegistryClient.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/RegistryClient.java new file mode 100644 index 00000000000000..f2b1e83075f0d6 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/RegistryClient.java @@ -0,0 +1,55 @@ +package io.quarkus.registry.client; + +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.RegistryResolutionException; +import io.quarkus.registry.catalog.ExtensionCatalog; +import io.quarkus.registry.catalog.PlatformCatalog; +import io.quarkus.registry.config.RegistryConfig; +import java.util.Objects; + +/** + * Implements the basic queries a registry client is supposed to handle. + * Although there are only a few kinds of queries, a registry is not required to support + * all of them. For example, a registry may be configured to only provide platform extensions or + * the other way around - provide only non-platform extensions but not platforms. + */ +public class RegistryClient + implements RegistryNonPlatformExtensionsResolver, RegistryPlatformExtensionsResolver, RegistryPlatformsResolver, + RegistryConfigResolver { + + private final RegistryPlatformsResolver platforms; + private final RegistryPlatformExtensionsResolver platformExtensions; + private final RegistryNonPlatformExtensionsResolver nonPlatformExtensions; + protected RegistryConfig config; + + public RegistryClient(RegistryConfig config, RegistryPlatformsResolver platforms, + RegistryPlatformExtensionsResolver platformExtensions, + RegistryNonPlatformExtensionsResolver nonPlatformExtensions) { + this.config = config; + this.platforms = platforms; + this.platformExtensions = Objects.requireNonNull(platformExtensions); + this.nonPlatformExtensions = nonPlatformExtensions; + } + + @Override + public PlatformCatalog resolvePlatforms(String quarkusVersion) throws RegistryResolutionException { + return platforms == null ? null : platforms.resolvePlatforms(quarkusVersion); + } + + @Override + public ExtensionCatalog resolvePlatformExtensions(ArtifactCoords platformCoords) + throws RegistryResolutionException { + return platformExtensions.resolvePlatformExtensions(platformCoords); + } + + @Override + public ExtensionCatalog resolveNonPlatformExtensions(String quarkusVersion) throws RegistryResolutionException { + return nonPlatformExtensions == null ? null + : nonPlatformExtensions.resolveNonPlatformExtensions(quarkusVersion); + } + + @Override + public RegistryConfig resolveRegistryConfig() throws RegistryResolutionException { + return config; + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/RegistryClientFactory.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/RegistryClientFactory.java new file mode 100644 index 00000000000000..fbfda63c8bf342 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/RegistryClientFactory.java @@ -0,0 +1,9 @@ +package io.quarkus.registry.client; + +import io.quarkus.registry.RegistryResolutionException; +import io.quarkus.registry.config.RegistryConfig; + +public interface RegistryClientFactory { + + RegistryClient buildRegistryClient(RegistryConfig config) throws RegistryResolutionException; +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/RegistryConfigResolver.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/RegistryConfigResolver.java new file mode 100644 index 00000000000000..39d7a64f072338 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/RegistryConfigResolver.java @@ -0,0 +1,17 @@ +package io.quarkus.registry.client; + +import io.quarkus.registry.RegistryResolutionException; +import io.quarkus.registry.config.RegistryConfig; + +public interface RegistryConfigResolver { + + /** + * Returns the complete registry configuration. The idea is that the default configuration + * to communicate with the registry will be provided by the registry admins for all users. + * Users though will still have a chance to adjust certain config options on the client side. + * + * @return complete registry configuration + * @throws RegistryResolutionException in case of a failure + */ + RegistryConfig resolveRegistryConfig() throws RegistryResolutionException; +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/RegistryNonPlatformExtensionsResolver.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/RegistryNonPlatformExtensionsResolver.java new file mode 100644 index 00000000000000..90cacf5a35a8b2 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/RegistryNonPlatformExtensionsResolver.java @@ -0,0 +1,19 @@ +package io.quarkus.registry.client; + +import io.quarkus.registry.RegistryResolutionException; +import io.quarkus.registry.catalog.ExtensionCatalog; + +public interface RegistryNonPlatformExtensionsResolver { + + /** + * Returns a catalog of extensions that are compatible with a given Quarkus version + * or null, in case the registry does not include any extension that is compatible + * with the given Quarkus version. + * + * @param quarkusVersion Quarkus version + * @return catalog of extensions compatible with a given Quarkus version or null + * @throws RegistryResolutionException in case of a failure + */ + ExtensionCatalog resolveNonPlatformExtensions(String quarkusVersion) + throws RegistryResolutionException; +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/RegistryPlatformExtensionsResolver.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/RegistryPlatformExtensionsResolver.java new file mode 100644 index 00000000000000..d8cfafda00256e --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/RegistryPlatformExtensionsResolver.java @@ -0,0 +1,18 @@ +package io.quarkus.registry.client; + +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.RegistryResolutionException; +import io.quarkus.registry.catalog.ExtensionCatalog; + +public interface RegistryPlatformExtensionsResolver { + + /** + * Returns a catalog of extensions that represents a given platform. + * + * @param platformCoords either a BOM or a JSON descriptor coordinates + * @return catalog of extensions that represents the platform + * @throws RegistryResolutionException in case of a failure + */ + ExtensionCatalog resolvePlatformExtensions(ArtifactCoords platformCoords) + throws RegistryResolutionException; +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/RegistryPlatformsResolver.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/RegistryPlatformsResolver.java new file mode 100644 index 00000000000000..f54594552676ea --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/RegistryPlatformsResolver.java @@ -0,0 +1,18 @@ +package io.quarkus.registry.client; + +import io.quarkus.registry.RegistryResolutionException; +import io.quarkus.registry.catalog.PlatformCatalog; + +public interface RegistryPlatformsResolver { + + /** + * Returns a catalog of the recommended platform versions, indicating which one of them + * is the default one for new project creation, for a given Quarkus version or in general, + * in case the caller did not provide any specific Quarkus version. + * + * @param quarkusVersion Quarkus version or null + * @return catalog of the recommended platform versions + * @throws RegistryResolutionException in case of a failure + */ + PlatformCatalog resolvePlatforms(String quarkusVersion) throws RegistryResolutionException; +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/maven/MavenNonPlatformExtensionsResolver.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/maven/MavenNonPlatformExtensionsResolver.java new file mode 100644 index 00000000000000..167aeffb1289dd --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/maven/MavenNonPlatformExtensionsResolver.java @@ -0,0 +1,51 @@ +package io.quarkus.registry.client.maven; + +import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; +import io.quarkus.devtools.messagewriter.MessageWriter; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.RegistryResolutionException; +import io.quarkus.registry.catalog.ExtensionCatalog; +import io.quarkus.registry.catalog.json.JsonCatalogMapperHelper; +import io.quarkus.registry.catalog.json.JsonExtensionCatalog; +import io.quarkus.registry.client.RegistryNonPlatformExtensionsResolver; +import io.quarkus.registry.config.RegistryNonPlatformExtensionsConfig; +import java.nio.file.Path; +import java.util.Objects; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.DefaultArtifact; + +public class MavenNonPlatformExtensionsResolver + implements RegistryNonPlatformExtensionsResolver { + + private final RegistryNonPlatformExtensionsConfig config; + private final MavenArtifactResolver artifactResolver; + private final MessageWriter log; + + public MavenNonPlatformExtensionsResolver(RegistryNonPlatformExtensionsConfig config, + MavenArtifactResolver artifactResolver, MessageWriter log) { + this.config = Objects.requireNonNull(config); + this.artifactResolver = Objects.requireNonNull(artifactResolver); + this.log = Objects.requireNonNull(log); + } + + @Override + public ExtensionCatalog resolveNonPlatformExtensions(String quarkusVersion) + throws RegistryResolutionException { + final ArtifactCoords baseCoords = config.getArtifact(); + final Artifact catalogArtifact = new DefaultArtifact(baseCoords.getGroupId(), + baseCoords.getArtifactId(), quarkusVersion, baseCoords.getType(), baseCoords.getVersion()); + log.debug("Resolving non-platform extension catalog %s", catalogArtifact); + final Path jsonFile; + try { + jsonFile = artifactResolver.resolve(catalogArtifact).getArtifact().getFile().toPath(); + } catch (Exception e) { + log.debug("Failed to resolve non-platform extension catalog %s", catalogArtifact); + return null; + } + try { + return JsonCatalogMapperHelper.deserialize(jsonFile, JsonExtensionCatalog.class); + } catch (Exception e) { + throw new RegistryResolutionException("Failed to load non-platform extension catalog from " + jsonFile, e); + } + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/maven/MavenPlatformExtensionsResolver.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/maven/MavenPlatformExtensionsResolver.java new file mode 100644 index 00000000000000..84603090c98aba --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/maven/MavenPlatformExtensionsResolver.java @@ -0,0 +1,93 @@ +package io.quarkus.registry.client.maven; + +import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; +import io.quarkus.devtools.messagewriter.MessageWriter; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.Constants; +import io.quarkus.registry.RegistryResolutionException; +import io.quarkus.registry.catalog.ExtensionCatalog; +import io.quarkus.registry.catalog.json.JsonCatalogMapperHelper; +import io.quarkus.registry.catalog.json.JsonExtensionCatalog; +import io.quarkus.registry.client.RegistryPlatformExtensionsResolver; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Objects; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.DefaultArtifact; + +public class MavenPlatformExtensionsResolver implements RegistryPlatformExtensionsResolver { + + private final MavenArtifactResolver artifactResolver; + private final MessageWriter log; + + public MavenPlatformExtensionsResolver(MavenArtifactResolver artifactResolver, + MessageWriter log) { + this.artifactResolver = Objects.requireNonNull(artifactResolver); + this.log = Objects.requireNonNull(log); + } + + @Override + public ExtensionCatalog resolvePlatformExtensions(ArtifactCoords platformCoords) throws RegistryResolutionException { + final String version; + if (platformCoords.getVersion() == null) { + version = resolveLatestBomVersion(platformCoords, "[0-alpha,)"); + } else if (isVersionRange(platformCoords.getVersion())) { + version = resolveLatestBomVersion(platformCoords, platformCoords.getVersion()); + } else { + version = platformCoords.getVersion(); + } + final String groupId = platformCoords.getGroupId(); + final String artifactId = platformCoords.getArtifactId().endsWith(Constants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX) + ? platformCoords.getArtifactId() + : platformCoords.getArtifactId() + Constants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX; + final String classifier = version; + final Artifact catalogArtifact = new DefaultArtifact(groupId, artifactId, classifier, "json", version); + log.debug("Resolving platform extension catalog %s", catalogArtifact); + final Path jsonPath; + try { + jsonPath = artifactResolver.resolve(catalogArtifact).getArtifact().getFile().toPath(); + } catch (Exception e) { + throw new RegistryResolutionException("Failed to resolve Quarkus extensions catalog " + catalogArtifact, + e); + } + try { + return JsonCatalogMapperHelper.deserialize(jsonPath, JsonExtensionCatalog.class); + } catch (IOException e) { + throw new RegistryResolutionException("Failed to parse Quarkus extensions catalog " + jsonPath, e); + } + } + + private String resolveLatestBomVersion(ArtifactCoords bom, String versionRange) + throws RegistryResolutionException { + final Artifact bomArtifact = new DefaultArtifact(bom.getGroupId(), + bom.getArtifactId().endsWith(Constants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX) + ? bom.getArtifactId().substring(0, + bom.getArtifactId().length() + - Constants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX.length()) + : bom.getArtifactId(), + "", "pom", bom.getVersion()); + log.debug("Resolving the latest version of %s:%s:%s:%s in the range %s", bom.getGroupId(), bom.getArtifactId(), + bom.getClassifier(), bom.getType(), versionRange); + try { + return artifactResolver.getLatestVersionFromRange(bomArtifact, versionRange); + } catch (Exception e) { + throw new RegistryResolutionException("Failed to resolve the latest version of " + bomArtifact.getGroupId() + + ":" + bom.getArtifactId() + ":" + bom.getClassifier() + ":" + bom.getType() + ":" + versionRange, e); + } + } + + private static boolean isVersionRange(String versionStr) { + if (versionStr == null || versionStr.isEmpty()) { + return false; + } + char c = versionStr.charAt(0); + if (c == '[' || c == '(') { + return true; + } + c = versionStr.charAt(versionStr.length() - 1); + if (c == ']' || c == ')') { + return true; + } + return versionStr.indexOf(',') >= 0; + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/maven/MavenPlatformsResolver.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/maven/MavenPlatformsResolver.java new file mode 100644 index 00000000000000..a9056846ef1a9a --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/maven/MavenPlatformsResolver.java @@ -0,0 +1,51 @@ +package io.quarkus.registry.client.maven; + +import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; +import io.quarkus.devtools.messagewriter.MessageWriter; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.RegistryResolutionException; +import io.quarkus.registry.catalog.PlatformCatalog; +import io.quarkus.registry.catalog.json.JsonCatalogMapperHelper; +import io.quarkus.registry.catalog.json.JsonPlatformCatalog; +import io.quarkus.registry.client.RegistryPlatformsResolver; +import io.quarkus.registry.config.RegistryPlatformsConfig; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Objects; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.DefaultArtifact; + +public class MavenPlatformsResolver implements RegistryPlatformsResolver { + + private final RegistryPlatformsConfig config; + private final MavenArtifactResolver artifactResolver; + private final MessageWriter log; + + public MavenPlatformsResolver(RegistryPlatformsConfig config, MavenArtifactResolver artifactResolver, + MessageWriter log) { + this.config = Objects.requireNonNull(config); + this.artifactResolver = Objects.requireNonNull(artifactResolver); + this.log = Objects.requireNonNull(log); + } + + @Override + public PlatformCatalog resolvePlatforms(String quarkusVersion) throws RegistryResolutionException { + final ArtifactCoords baseCoords = config.getArtifact(); + final Artifact catalogArtifact = new DefaultArtifact(baseCoords.getGroupId(), baseCoords.getArtifactId(), + quarkusVersion, baseCoords.getType(), baseCoords.getVersion()); + log.debug("Resolving platform catalog %s", catalogArtifact); + final Path jsonFile; + try { + jsonFile = artifactResolver.resolve(catalogArtifact).getArtifact().getFile().toPath(); + } catch (Exception e) { + log.debug("Failed to resolve platform catalog %s", catalogArtifact); + return null; + } + try { + return JsonCatalogMapperHelper.deserialize(jsonFile, JsonPlatformCatalog.class); + } catch (IOException e) { + throw new RegistryResolutionException( + "Failed to load platform catalog from " + jsonFile, e); + } + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/maven/MavenRegistryClientFactory.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/maven/MavenRegistryClientFactory.java new file mode 100644 index 00000000000000..78b94b1a10a86d --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/client/maven/MavenRegistryClientFactory.java @@ -0,0 +1,368 @@ +package io.quarkus.registry.client.maven; + +import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContext; +import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; +import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; +import io.quarkus.devtools.messagewriter.MessageWriter; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.Constants; +import io.quarkus.registry.RegistryResolutionException; +import io.quarkus.registry.client.RegistryClient; +import io.quarkus.registry.client.RegistryClientFactory; +import io.quarkus.registry.client.RegistryNonPlatformExtensionsResolver; +import io.quarkus.registry.client.RegistryPlatformsResolver; +import io.quarkus.registry.config.RegistryArtifactConfig; +import io.quarkus.registry.config.RegistryConfig; +import io.quarkus.registry.config.RegistryDescriptorConfig; +import io.quarkus.registry.config.RegistryMavenConfig; +import io.quarkus.registry.config.RegistryMavenRepoConfig; +import io.quarkus.registry.config.RegistryNonPlatformExtensionsConfig; +import io.quarkus.registry.config.RegistryPlatformsConfig; +import io.quarkus.registry.config.json.JsonRegistryConfig; +import io.quarkus.registry.config.json.JsonRegistryMavenConfig; +import io.quarkus.registry.config.json.JsonRegistryMavenRepoConfig; +import io.quarkus.registry.config.json.JsonRegistryPlatformsConfig; +import io.quarkus.registry.config.json.RegistriesConfigMapperHelper; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.repository.RepositoryPolicy; +import org.eclipse.aether.resolution.ArtifactResult; + +public class MavenRegistryClientFactory implements RegistryClientFactory { + + private MessageWriter log; + private MavenArtifactResolver originalResolver; + private List<RemoteRepository> singleRegistryRepos = new ArrayList<RemoteRepository>(); + + public MavenRegistryClientFactory(MavenArtifactResolver resolver, MessageWriter log) { + this.originalResolver = Objects.requireNonNull(resolver); + this.log = Objects.requireNonNull(log); + } + + @Override + public RegistryClient buildRegistryClient(RegistryConfig config) throws RegistryResolutionException { + Objects.requireNonNull(config, "The registry config is null"); + + final RegistryDescriptorConfig descriptorConfig = Objects.requireNonNull(config.getDescriptor(), + "The registry descriptor configuration is missing"); + + MavenArtifactResolver resolver = originalResolver; + + singleRegistryRepos.clear(); + determineExtraRepos(config, resolver.getRepositories()); + + List<RemoteRepository> aggregatedRepos = resolver.getRepositories(); + if (!singleRegistryRepos.isEmpty()) { + aggregatedRepos = resolver.getRemoteRepositoryManager().aggregateRepositories(resolver.getSession(), + Collections.emptyList(), singleRegistryRepos, true); + aggregatedRepos = resolver.getRemoteRepositoryManager().aggregateRepositories(resolver.getSession(), + aggregatedRepos, resolver.getRepositories(), false); + resolver = newResolver(resolver, aggregatedRepos); + } + + final ArtifactCoords originalDescrCoords = descriptorConfig.getArtifact(); + final Artifact registryDescriptorCoords = new DefaultArtifact(originalDescrCoords.getGroupId(), + originalDescrCoords.getArtifactId(), originalDescrCoords.getClassifier(), originalDescrCoords.getType(), + originalDescrCoords.getVersion()); + ArtifactResult result; + try { + result = resolver.resolve(registryDescriptorCoords); + } catch (BootstrapMavenException e) { + final StringWriter buf = new StringWriter(); + try (BufferedWriter writer = new BufferedWriter(buf)) { + writer.write("Failed to resolve Quarkus extensions registry descriptor "); + writer.write(registryDescriptorCoords.toString()); + writer.write(" using the following repositories:"); + for (RemoteRepository repo : aggregatedRepos) { + writer.newLine(); + writer.write("- "); + writer.write(repo.getId()); + writer.write(" ("); + writer.write(repo.getUrl()); + writer.write(")"); + } + } catch (IOException e1) { + buf.append(e.getLocalizedMessage()); + } + throw new RegistryResolutionException(buf.toString()); + } + + final String srcRepoId = result.getRepository() == null ? "n/a" : result.getRepository().getId(); + log.debug("Resolved registry descriptor %s from %s", registryDescriptorCoords, srcRepoId); + if (!singleRegistryRepos.isEmpty()) { + if (srcRepoId != null && !"local".equals(srcRepoId)) { + String srcRepoUrl = null; + for (RemoteRepository repo : resolver.getRepositories()) { + if (repo.getId().equals(srcRepoId)) { + srcRepoUrl = repo.getUrl(); + break; + } + } + if (srcRepoUrl == null) { + throw new IllegalStateException( + "Failed to locate the repository URL corresponding to repository " + srcRepoId); + } + } else { + log.debug("Failed to determine the remote repository for %s registry descriptor %s", config.getId(), + registryDescriptorCoords); + } + } + + final RegistryConfig descriptor; + try { + descriptor = RegistriesConfigMapperHelper.deserialize(result.getArtifact().getFile().toPath(), + JsonRegistryConfig.class); + } catch (IOException e) { + throw new IllegalStateException("Failed to deserialize registries descriptor " + result.getArtifact().getFile(), e); + } + + if (!isComplete(config, descriptor)) { + final JsonRegistryConfig complete = new JsonRegistryConfig(); + complete(complete, config, descriptor); + config = complete; + } + + final RegistryNonPlatformExtensionsResolver nonPlatformExtensionsResolver; + final RegistryNonPlatformExtensionsConfig nonPlatformExtensions = config.getNonPlatformExtensions(); + if (nonPlatformExtensions == null || nonPlatformExtensions.isDisabled()) { + log.debug("Non-platform extension catalogs were disabled for registry %s", config.getId()); + nonPlatformExtensionsResolver = null; + } else { + nonPlatformExtensionsResolver = new MavenNonPlatformExtensionsResolver(nonPlatformExtensions, + resolver, log); + } + + final RegistryPlatformsResolver platformsResolver; + final RegistryPlatformsConfig platformsConfig = config.getPlatforms(); + if (platformsConfig == null || platformsConfig.isDisabled()) { + log.debug("Platform catalogs were disabled for registry %s", config.getId()); + platformsResolver = null; + } else { + platformsResolver = new MavenPlatformsResolver(platformsConfig, resolver, log); + } + + return new RegistryClient(config, platformsResolver, + Boolean.TRUE.equals(config.getPlatforms().getExtensionCatalogsIncluded()) + ? new MavenPlatformExtensionsResolver(resolver, log) + : new MavenPlatformExtensionsResolver(originalResolver, log), + nonPlatformExtensionsResolver); + } + + private static void complete(JsonRegistryConfig complete, RegistryConfig original, RegistryConfig descriptor) { + complete.setId(original.getId() == null ? descriptor.getId() : original.getId()); + + if (original.getDescriptor() == null) { + complete.setDescriptor(descriptor.getDescriptor()); + } else { + complete.setDescriptor(original.getDescriptor()); + } + if (original.getPlatforms() == null) { + complete.setPlatforms(descriptor.getPlatforms()); + } else { + complete.setPlatforms(complete(original.getPlatforms(), descriptor.getPlatforms())); + } + if (original.getNonPlatformExtensions() == null) { + complete.setNonPlatformExtensions(descriptor.getNonPlatformExtensions()); + } else { + complete.setNonPlatformExtensions(descriptor.getNonPlatformExtensions()); + } + + if (original.getUpdatePolicy() == null) { + complete.setUpdatePolicy(descriptor.getUpdatePolicy()); + } else { + complete.setUpdatePolicy(original.getUpdatePolicy()); + } + + if (original.getMaven() == null) { + complete.setMaven(descriptor.getMaven()); + } else if (isComplete(original.getMaven())) { + complete.setMaven(original.getMaven()); + } else { + final JsonRegistryMavenConfig completeMavenConfig = new JsonRegistryMavenConfig(); + complete.setMaven(completeMavenConfig); + complete(completeMavenConfig, original.getMaven(), + descriptor.getMaven() == null ? completeMavenConfig : descriptor.getMaven()); + } + if (original.getQuarkusVersions() == null) { + complete.setQuarkusVersions(descriptor.getQuarkusVersions()); + } + } + + private static RegistryPlatformsConfig complete(RegistryPlatformsConfig client, RegistryPlatformsConfig descriptor) { + if (client == null) { + return descriptor; + } + if (isComplete(client)) { + return client; + } + JsonRegistryPlatformsConfig complete = new JsonRegistryPlatformsConfig(); + complete.setArtifact(client.getArtifact() == null ? descriptor.getArtifact() : client.getArtifact()); + complete.setDisabled(client.isDisabled()); + complete.setExtensionCatalogsIncluded( + client.getExtensionCatalogsIncluded() == null ? descriptor.getExtensionCatalogsIncluded() + : client.getExtensionCatalogsIncluded()); + return complete; + } + + private static void complete(JsonRegistryMavenConfig complete, RegistryMavenConfig original, + RegistryMavenConfig descriptor) { + if (original.getRepository() == null) { + complete.setRepository(descriptor.getRepository()); + } else if (isComplete(original.getRepository()) || descriptor.getRepository() == null) { + complete.setRepository(original.getRepository()); + } else { + final JsonRegistryMavenRepoConfig completeRepo = new JsonRegistryMavenRepoConfig(); + complete.setRepository(completeRepo); + complete(completeRepo, original.getRepository(), descriptor.getRepository()); + } + } + + private static void complete(JsonRegistryMavenRepoConfig complete, RegistryMavenRepoConfig original, + RegistryMavenRepoConfig descriptor) { + complete.setId(original.getId() == null ? descriptor.getId() : original.getId()); + complete.setUrl(original.getUrl() == null ? descriptor.getUrl() : original.getUrl()); + } + + private static boolean isComplete(RegistryConfig client, RegistryConfig descriptor) { + if (client.isDisabled()) { + return true; + } + if (client.getDescriptor() == null) { + return false; + } + if (!isComplete(client.getPlatforms(), descriptor.getPlatforms())) { + return false; + } + if (!isComplete(client.getNonPlatformExtensions())) { + return false; + } + if (!isComplete(client.getMaven())) { + return false; + } + if (client.getQuarkusVersions() == null && descriptor.getQuarkusVersions() != null) { + return false; + } + if (client.getUpdatePolicy() == null && descriptor.getUpdatePolicy() != null) { + return false; + } + return true; + } + + private static boolean isComplete(RegistryMavenConfig config) { + if (config == null) { + return false; + } + if (!isComplete(config.getRepository())) { + return false; + } + return true; + } + + private static boolean isComplete(RegistryPlatformsConfig client, RegistryPlatformsConfig descriptor) { + if (!isComplete(client)) { + return false; + } + if (descriptor != null && Boolean.TRUE.equals(descriptor.getExtensionCatalogsIncluded()) + && client.getExtensionCatalogsIncluded() == null) { + return false; + } + return true; + } + + private static boolean isComplete(RegistryArtifactConfig config) { + if (config == null) { + return false; + } + if (!config.isDisabled() && config.getArtifact() == null) { + return false; + } + return true; + } + + private static boolean isComplete(RegistryMavenRepoConfig config) { + if (config == null) { + return false; + } + if (config.getId() == null) { + return false; + } + if (config.getUrl() == null) { + return false; + } + return true; + } + + private static MavenArtifactResolver newResolver(MavenArtifactResolver resolver, List<RemoteRepository> aggregatedRepos) { + try { + final BootstrapMavenContext mvnCtx = new BootstrapMavenContext( + BootstrapMavenContext.config() + .setRepositorySystem(resolver.getSystem()) + .setRepositorySystemSession(resolver.getSession()) + .setRemoteRepositoryManager(resolver.getRemoteRepositoryManager()) + .setRemoteRepositories(aggregatedRepos) + .setLocalRepository(resolver.getMavenContext().getLocalRepo()) + .setCurrentProject(resolver.getMavenContext().getCurrentProject())); + return new MavenArtifactResolver(mvnCtx); + } catch (BootstrapMavenException e) { + throw new IllegalStateException("Failed to initialize maven context", e); + } + } + + private void determineExtraRepos(RegistryConfig config, + List<RemoteRepository> configuredRepos) { + final RegistryMavenConfig mavenConfig = config.getMaven() == null ? null : config.getMaven(); + final RegistryMavenRepoConfig repoConfig = mavenConfig == null ? null : mavenConfig.getRepository(); + final String repoUrl = repoConfig == null || repoConfig.getUrl() == null + ? Constants.DEFAULT_REGISTRY_BACKUP_MAVEN_REPO_URL + : repoConfig.getUrl(); + addRegistryRepo(repoUrl, repoConfig == null || repoConfig.getId() == null ? config.getId() : repoConfig.getId(), + config.getUpdatePolicy(), + configuredRepos); + } + + private void addRegistryRepo(final String repoUrl, String defaultRepoId, String updatePolicy, + List<RemoteRepository> configuredRepos) { + final Set<String> ids = new HashSet<>(configuredRepos.size()); + for (RemoteRepository repo : configuredRepos) { + if (repo.getUrl().equals(repoUrl)) { + return; + } + ids.add(repo.getId()); + } + + String repoId = defaultRepoId; + if (ids.contains(repoId)) { + int i = 2; + String tmp; + do { + tmp = repoId + "-" + i++; + } while (!ids.contains(tmp)); + repoId = tmp; + } + + final RemoteRepository.Builder repoBuilder = new RemoteRepository.Builder(repoId, "default", repoUrl); + + if (updatePolicy != null) { + if (updatePolicy.equalsIgnoreCase(RepositoryPolicy.UPDATE_POLICY_DAILY) + || updatePolicy.equalsIgnoreCase(RepositoryPolicy.UPDATE_POLICY_ALWAYS) + || updatePolicy.equalsIgnoreCase(RepositoryPolicy.UPDATE_POLICY_NEVER) + || updatePolicy.startsWith(RepositoryPolicy.UPDATE_POLICY_INTERVAL)) { + repoBuilder.setPolicy(new RepositoryPolicy(true, updatePolicy, RepositoryPolicy.CHECKSUM_POLICY_WARN)); + } else { + throw new IllegalStateException("Unrecognized update policy '" + updatePolicy + "' for repository " + repoId); + } + } + + singleRegistryRepos.add(repoBuilder.build()); + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/PropertiesUtil.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/PropertiesUtil.java new file mode 100644 index 00000000000000..f8a22577b0cbac --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/PropertiesUtil.java @@ -0,0 +1,66 @@ +package io.quarkus.registry.config; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Locale; + +public class PropertiesUtil { + + private static final String OS_NAME = "os.name"; + private static final String USER_HOME = "user.home"; + private static final String WINDOWS = "windows"; + + private static final String FALSE = "false"; + private static final String TRUE = "true"; + + private PropertiesUtil() { + } + + public static boolean isWindows() { + return getProperty(OS_NAME).toLowerCase(Locale.ENGLISH).contains(WINDOWS); + } + + public static String getUserHome() { + return getProperty(USER_HOME); + } + + public static String getProperty(final String name, String defValue) { + assert name != null : "name is null"; + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + return AccessController.doPrivileged(new PrivilegedAction<String>() { + @Override + public String run() { + return System.getProperty(name, defValue); + } + }); + } else { + return System.getProperty(name, defValue); + } + } + + public static String getProperty(final String name) { + assert name != null : "name is null"; + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + return AccessController.doPrivileged(new PrivilegedAction<String>() { + @Override + public String run() { + return System.getProperty(name); + } + }); + } else { + return System.getProperty(name); + } + } + + public static final Boolean getBooleanOrNull(String name) { + final String value = getProperty(name); + return value == null ? null : Boolean.parseBoolean(value); + } + + public static final boolean getBoolean(String name, boolean notFoundValue) { + final String value = getProperty(name, (notFoundValue ? TRUE : FALSE)); + return value.isEmpty() ? true : Boolean.parseBoolean(value); + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistriesConfig.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistriesConfig.java new file mode 100644 index 00000000000000..80357d5e6d3298 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistriesConfig.java @@ -0,0 +1,10 @@ +package io.quarkus.registry.config; + +import java.util.List; + +public interface RegistriesConfig { + + boolean isDebug(); + + List<RegistryConfig> getRegistries(); +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistriesConfigLocator.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistriesConfigLocator.java new file mode 100644 index 00000000000000..9b83b2062f4700 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistriesConfigLocator.java @@ -0,0 +1,203 @@ +package io.quarkus.registry.config; + +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.Constants; +import io.quarkus.registry.config.json.JsonRegistriesConfig; +import io.quarkus.registry.config.json.JsonRegistryConfig; +import io.quarkus.registry.config.json.JsonRegistryDescriptorConfig; +import io.quarkus.registry.config.json.JsonRegistryMavenConfig; +import io.quarkus.registry.config.json.JsonRegistryMavenRepoConfig; +import io.quarkus.registry.config.json.JsonRegistryNonPlatformExtensionsConfig; +import io.quarkus.registry.config.json.JsonRegistryPlatformsConfig; +import io.quarkus.registry.config.json.RegistriesConfigMapperHelper; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Objects; + +public class RegistriesConfigLocator { + + public static final String CONFIG_RELATIVE_PATH = ".quarkus/config.yaml"; + public static final String CONFIG_FILE_PATH_PROPERTY = "qer.config"; + + public static RegistriesConfig resolveConfig() { + final Path configYaml = locateConfigYaml(); + if (configYaml == null) { + return completeRequiredConfig(new JsonRegistriesConfig()); + } + return load(configYaml); + } + + public static RegistriesConfig load(Path configYaml) { + try { + return completeRequiredConfig(RegistriesConfigMapperHelper.deserialize(configYaml, JsonRegistriesConfig.class)); + } catch (IOException e) { + throw new IllegalStateException("Failed to parse config file " + configYaml, e); + } + } + + public static RegistriesConfig load(InputStream configYaml) { + try { + return completeRequiredConfig(RegistriesConfigMapperHelper.deserializeYaml(configYaml, JsonRegistriesConfig.class)); + } catch (IOException e) { + throw new IllegalStateException("Failed to parse config file " + configYaml, e); + } + } + + private static Path locateConfigYaml() { + final String prop = PropertiesUtil.getProperty(CONFIG_FILE_PATH_PROPERTY); + Path configYaml; + if (prop != null) { + configYaml = Paths.get(prop); + if (!Files.exists(configYaml)) { + throw new IllegalStateException("Quarkus extensions registry configuration file " + configYaml + + " specified with the system property " + CONFIG_FILE_PATH_PROPERTY + " does not exist"); + } + return configYaml; + } + configYaml = Paths.get("").normalize().toAbsolutePath().resolve(CONFIG_RELATIVE_PATH); + if (Files.exists(configYaml)) { + return configYaml; + } + configYaml = Paths.get(PropertiesUtil.getProperty("user.home")).resolve(CONFIG_RELATIVE_PATH); + return Files.exists(configYaml) ? configYaml : null; + } + + private static RegistriesConfig completeRequiredConfig(RegistriesConfig original) { + final JsonRegistriesConfig config = new JsonRegistriesConfig(); + config.setDebug(original.isDebug()); + if (original.getRegistries().isEmpty()) { + config.addRegistry(getDefaultRegistry()); + } else { + for (RegistryConfig qerConfig : original.getRegistries()) { + if (!qerConfig.isDisabled()) { + config.addRegistry(completeRequiredConfig(qerConfig)); + } + } + if (config.isEmpty()) { + config.addRegistry(getDefaultRegistry()); + } + } + return config; + } + + private static RegistryConfig completeRequiredConfig(RegistryConfig original) { + if (hasRequiredConfig(original)) { + return original; + } + final String id = original.getId(); + final JsonRegistryConfig config = new JsonRegistryConfig(id); + config.setUpdatePolicy(original.getUpdatePolicy()); + config.setDescriptor(completeDescriptor(original)); + config.setMaven(completeRequiedMavenConfig(original)); + if (original != null) { + if (original.getNonPlatformExtensions() != null) { + config.setNonPlatformExtensions(original.getNonPlatformExtensions()); + } + if (original.getPlatforms() != null) { + config.setPlatforms(original.getPlatforms()); + } + } + return config; + } + + private static RegistryMavenConfig completeRequiedMavenConfig(RegistryConfig original) { + RegistryMavenConfig originalMaven = original.getMaven(); + if (hasRequiredConfig(originalMaven)) { + return originalMaven; + } + final JsonRegistryMavenConfig config = new JsonRegistryMavenConfig(); + if (originalMaven != null) { + config.setRepository(originalMaven.getRepository()); + } + return config; + } + + private static RegistryDescriptorConfig completeDescriptor(RegistryConfig config) { + if (config.getDescriptor() != null && config.getDescriptor().getArtifact() != null) { + return config.getDescriptor(); + } + final JsonRegistryDescriptorConfig descriptor = new JsonRegistryDescriptorConfig(); + String host = config.getId(); + if (host == null) { + final RegistryMavenRepoConfig repo = config.getMaven() == null ? null : config.getMaven().getRepository(); + if (repo != null && repo.getUrl() != null) { + throw new IllegalStateException( + "Failed to determine the descriptor coordinates for a registry with no ID and no Maven configuration"); + } + host = Objects.requireNonNull(toUrlOrNull(repo.getUrl()), "REST endpoint is not a valid URL").getHost(); + } + final String[] parts = host.split("\\."); + final StringBuilder buf = new StringBuilder(host.length()); + int i = parts.length; + buf.append(parts[--i]); + while (--i >= 0) { + buf.append('.').append(parts[i]); + } + descriptor.setArtifact( + new ArtifactCoords(buf.toString(), Constants.DEFAULT_REGISTRY_DESCRIPTOR_ARTIFACT_ID, null, Constants.JSON, + Constants.DEFAULT_REGISTRY_ARTIFACT_VERSION)); + return descriptor; + } + + private static URL toUrlOrNull(String str) { + try { + return new URL(str); + } catch (MalformedURLException e) { + } + return null; + } + + private static boolean hasRequiredConfig(RegistryConfig qerConfig) { + if (qerConfig.getId() == null) { + return false; + } + if (qerConfig.getDescriptor() == null) { + return false; + } + return hasRequiredConfig(qerConfig.getMaven()); + } + + private static boolean hasRequiredConfig(RegistryMavenConfig maven) { + if (maven == null) { + return false; + } + return true; + } + + public static RegistryConfig getDefaultRegistry() { + final JsonRegistryConfig qer = new JsonRegistryConfig(); + qer.setId(Constants.DEFAULT_REGISTRY_ID); + + final JsonRegistryDescriptorConfig descriptor = new JsonRegistryDescriptorConfig(); + qer.setDescriptor(descriptor); + descriptor.setArtifact( + new ArtifactCoords(Constants.DEFAULT_REGISTRY_GROUP_ID, Constants.DEFAULT_REGISTRY_DESCRIPTOR_ARTIFACT_ID, null, + Constants.JSON, Constants.DEFAULT_REGISTRY_ARTIFACT_VERSION)); + + final JsonRegistryMavenConfig mavenConfig = new JsonRegistryMavenConfig(); + qer.setMaven(mavenConfig); + + final JsonRegistryPlatformsConfig platformsConfig = new JsonRegistryPlatformsConfig(); + qer.setPlatforms(platformsConfig); + platformsConfig.setArtifact(new ArtifactCoords(Constants.DEFAULT_REGISTRY_GROUP_ID, + Constants.DEFAULT_REGISTRY_PLATFORMS_CATALOG_ARTIFACT_ID, null, Constants.JSON, + Constants.DEFAULT_REGISTRY_ARTIFACT_VERSION)); + + final JsonRegistryNonPlatformExtensionsConfig nonPlatformExtensionsConfig = new JsonRegistryNonPlatformExtensionsConfig(); + qer.setNonPlatformExtensions(nonPlatformExtensionsConfig); + nonPlatformExtensionsConfig.setArtifact(new ArtifactCoords(Constants.DEFAULT_REGISTRY_GROUP_ID, + Constants.DEFAULT_REGISTRY_NON_PLATFORM_EXTENSIONS_CATALOG_ARTIFACT_ID, null, Constants.JSON, + Constants.DEFAULT_REGISTRY_ARTIFACT_VERSION)); + + final JsonRegistryMavenRepoConfig mavenRepo = new JsonRegistryMavenRepoConfig(); + mavenConfig.setRepository(mavenRepo); + mavenRepo.setId(Constants.DEFAULT_REGISTRY_ID); + mavenRepo.setUrl(Constants.DEFAULT_REGISTRY_MAVEN_REPO_URL); + return qer; + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryArtifactConfig.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryArtifactConfig.java new file mode 100644 index 00000000000000..55cdcb8a34a701 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryArtifactConfig.java @@ -0,0 +1,10 @@ +package io.quarkus.registry.config; + +import io.quarkus.maven.ArtifactCoords; + +public interface RegistryArtifactConfig { + + boolean isDisabled(); + + ArtifactCoords getArtifact(); +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryConfig.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryConfig.java new file mode 100644 index 00000000000000..ef758108e7c272 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryConfig.java @@ -0,0 +1,20 @@ +package io.quarkus.registry.config; + +public interface RegistryConfig { + + String getId(); + + boolean isDisabled(); + + String getUpdatePolicy(); + + RegistryDescriptorConfig getDescriptor(); + + RegistryPlatformsConfig getPlatforms(); + + RegistryNonPlatformExtensionsConfig getNonPlatformExtensions(); + + RegistryMavenConfig getMaven(); + + RegistryQuarkusVersionsConfig getQuarkusVersions(); +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryDescriptorConfig.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryDescriptorConfig.java new file mode 100644 index 00000000000000..3c1fce320611f9 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryDescriptorConfig.java @@ -0,0 +1,8 @@ +package io.quarkus.registry.config; + +import io.quarkus.maven.ArtifactCoords; + +public interface RegistryDescriptorConfig { + + ArtifactCoords getArtifact(); +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryMavenConfig.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryMavenConfig.java new file mode 100644 index 00000000000000..0154206d866fdb --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryMavenConfig.java @@ -0,0 +1,6 @@ +package io.quarkus.registry.config; + +public interface RegistryMavenConfig { + + RegistryMavenRepoConfig getRepository(); +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryMavenRepoConfig.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryMavenRepoConfig.java new file mode 100644 index 00000000000000..601d352246efd3 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryMavenRepoConfig.java @@ -0,0 +1,8 @@ +package io.quarkus.registry.config; + +public interface RegistryMavenRepoConfig { + + String getId(); + + String getUrl(); +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryNonPlatformExtensionsConfig.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryNonPlatformExtensionsConfig.java new file mode 100644 index 00000000000000..e0999e39a91d61 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryNonPlatformExtensionsConfig.java @@ -0,0 +1,5 @@ +package io.quarkus.registry.config; + +public interface RegistryNonPlatformExtensionsConfig extends RegistryArtifactConfig { + +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryPlatformsConfig.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryPlatformsConfig.java new file mode 100644 index 00000000000000..405dbd2c696392 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryPlatformsConfig.java @@ -0,0 +1,6 @@ +package io.quarkus.registry.config; + +public interface RegistryPlatformsConfig extends RegistryArtifactConfig { + + Boolean getExtensionCatalogsIncluded(); +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryQuarkusVersionsConfig.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryQuarkusVersionsConfig.java new file mode 100644 index 00000000000000..1d3f2fa43b2dc9 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/RegistryQuarkusVersionsConfig.java @@ -0,0 +1,8 @@ +package io.quarkus.registry.config; + +public interface RegistryQuarkusVersionsConfig { + + String getRecognizedVersionsExpression(); + + boolean isExclusiveProvider(); +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistriesConfig.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistriesConfig.java new file mode 100644 index 00000000000000..920e76e8c544ff --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistriesConfig.java @@ -0,0 +1,50 @@ +package io.quarkus.registry.config.json; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.quarkus.registry.config.RegistriesConfig; +import io.quarkus.registry.config.RegistryConfig; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class JsonRegistriesConfig implements RegistriesConfig { + + private boolean debug; + private List<RegistryConfig> registries = Collections.emptyList(); + + @Override + @JsonDeserialize(contentUsing = JsonRegistryConfigDeserializer.class) + @JsonSerialize(contentUsing = JsonRegistryConfigSerializer.class) + public List<RegistryConfig> getRegistries() { + return registries; + } + + public void setRegistries(List<RegistryConfig> registries) { + this.registries = registries == null ? Collections.emptyList() : registries; + } + + public void addRegistry(RegistryConfig registry) { + if (registries.isEmpty()) { + registries = new ArrayList<>(); + } + registries.add(registry); + } + + @Override + public boolean isDebug() { + return debug; + } + + public void setDebug(boolean debug) { + this.debug = debug; + } + + @JsonIgnore + public boolean isEmpty() { + return registries.isEmpty(); + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryArtifactConfig.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryArtifactConfig.java new file mode 100644 index 00000000000000..8f36b29ab70dff --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryArtifactConfig.java @@ -0,0 +1,30 @@ +package io.quarkus.registry.config.json; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.config.RegistryArtifactConfig; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class JsonRegistryArtifactConfig implements RegistryArtifactConfig { + + protected boolean disabled; + protected ArtifactCoords artifact; + + @Override + public boolean isDisabled() { + return disabled; + } + + public void setDisabled(boolean disabled) { + this.disabled = disabled; + } + + @Override + public ArtifactCoords getArtifact() { + return artifact; + } + + public void setArtifact(ArtifactCoords artifact) { + this.artifact = artifact; + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryConfig.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryConfig.java new file mode 100644 index 00000000000000..f0edf0d9e7fca2 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryConfig.java @@ -0,0 +1,118 @@ +package io.quarkus.registry.config.json; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import io.quarkus.registry.config.RegistryConfig; +import io.quarkus.registry.config.RegistryDescriptorConfig; +import io.quarkus.registry.config.RegistryMavenConfig; +import io.quarkus.registry.config.RegistryNonPlatformExtensionsConfig; +import io.quarkus.registry.config.RegistryPlatformsConfig; +import io.quarkus.registry.config.RegistryQuarkusVersionsConfig; +import java.util.Objects; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class JsonRegistryConfig implements RegistryConfig { + + private String id; + private boolean disabled; + private String updatePolicy; + private RegistryDescriptorConfig descriptor; + private RegistryPlatformsConfig platforms; + private RegistryNonPlatformExtensionsConfig nonPlatformExtensions; + private RegistryMavenConfig mavenConfig; + private RegistryQuarkusVersionsConfig versionsConfig; + + public JsonRegistryConfig() { + } + + public JsonRegistryConfig(String id) { + this.id = Objects.requireNonNull(id, "QER ID can't be null"); + } + + @JsonIgnore + @Override + public String getId() { + return id; + } + + public void setId(String id) { + this.id = Objects.requireNonNull(id); + } + + @Override + public boolean isDisabled() { + return disabled; + } + + public void setDisabled(boolean disabled) { + this.disabled = disabled; + } + + @Override + public String getUpdatePolicy() { + return updatePolicy; + } + + public void setUpdatePolicy(String updatePolicy) { + this.updatePolicy = updatePolicy; + } + + @Override + @JsonDeserialize(as = JsonRegistryDescriptorConfig.class) + public RegistryDescriptorConfig getDescriptor() { + return descriptor; + } + + public void setDescriptor(RegistryDescriptorConfig descriptor) { + this.descriptor = descriptor; + } + + @JsonDeserialize(as = JsonRegistryPlatformsConfig.class) + @Override + public RegistryPlatformsConfig getPlatforms() { + return platforms; + } + + public void setPlatforms(RegistryPlatformsConfig platforms) { + this.platforms = platforms; + } + + @JsonDeserialize(as = JsonRegistryNonPlatformExtensionsConfig.class) + @Override + public RegistryNonPlatformExtensionsConfig getNonPlatformExtensions() { + return nonPlatformExtensions; + } + + public void setNonPlatformExtensions(RegistryNonPlatformExtensionsConfig nonPlatformExtensions) { + this.nonPlatformExtensions = nonPlatformExtensions; + } + + boolean isIdOnly() { + return mavenConfig == null; + } + + @JsonDeserialize(as = JsonRegistryMavenConfig.class) + @Override + public RegistryMavenConfig getMaven() { + return mavenConfig; + } + + public void setMaven(RegistryMavenConfig mavenConfig) { + this.mavenConfig = mavenConfig; + } + + @JsonDeserialize(as = JsonRegistryQuarkusVersionsConfig.class) + @Override + public RegistryQuarkusVersionsConfig getQuarkusVersions() { + return versionsConfig; + } + + public void setQuarkusVersions(RegistryQuarkusVersionsConfig quarkusVersions) { + this.versionsConfig = quarkusVersions; + } + + public String toString() { + return "[" + id + " maven=" + mavenConfig + "]"; + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryConfigDeserializer.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryConfigDeserializer.java new file mode 100644 index 00000000000000..7ca51a912b2e71 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryConfigDeserializer.java @@ -0,0 +1,35 @@ +package io.quarkus.registry.config.json; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.exc.InvalidFormatException; +import java.io.IOException; + +public class JsonRegistryConfigDeserializer extends JsonDeserializer<JsonRegistryConfig> { + + @Override + public JsonRegistryConfig deserialize(JsonParser p, DeserializationContext ctxt) + throws IOException, JsonProcessingException { + if (p.getCurrentToken() == JsonToken.VALUE_STRING) { + return new JsonRegistryConfig(p.getText()); + } else if (p.getCurrentToken() == JsonToken.START_OBJECT) { + ensureNextToken(p, JsonToken.FIELD_NAME, ctxt); + final String qerId = p.getCurrentName(); + ensureNextToken(p, JsonToken.START_OBJECT, ctxt); + final JsonRegistryConfig qer = p.readValueAs(JsonRegistryConfig.class); + qer.setId(qerId); + ensureNextToken(p, JsonToken.END_OBJECT, ctxt); + return qer; + } + return null; + } + + private void ensureNextToken(JsonParser p, JsonToken expected, DeserializationContext ctxt) throws IOException { + if (p.nextToken() != expected) { + throw InvalidFormatException.from(p, "Expected " + expected, ctxt, JsonRegistryConfig.class); + } + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryConfigSerializer.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryConfigSerializer.java new file mode 100644 index 00000000000000..f9a58756fceade --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryConfigSerializer.java @@ -0,0 +1,39 @@ +package io.quarkus.registry.config.json; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.BeanDescription; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.BeanSerializerFactory; +import java.io.IOException; + +public class JsonRegistryConfigSerializer extends JsonSerializer<JsonRegistryConfig> { + + private JsonSerializer<Object> qerSerializer; + + @Override + public void serialize(JsonRegistryConfig value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + if (value.isIdOnly()) { + gen.writeString(value.getId()); + } else { + gen.writeStartObject(); + gen.writeObjectFieldStart(value.getId()); + getQerSerializer(serializers).unwrappingSerializer(null).serialize(value, gen, serializers); + gen.writeEndObject(); + gen.writeEndObject(); + } + } + + private JsonSerializer<Object> getQerSerializer(SerializerProvider serializers) throws JsonMappingException { + if (qerSerializer == null) { + JavaType javaType = serializers.constructType(JsonRegistryConfig.class); + BeanDescription beanDesc = serializers.getConfig().introspect(javaType); + qerSerializer = BeanSerializerFactory.instance.findBeanOrAddOnSerializer(serializers, javaType, beanDesc, + serializers.isEnabled(MapperFeature.USE_STATIC_TYPING)); + } + return qerSerializer; + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryDescriptorConfig.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryDescriptorConfig.java new file mode 100644 index 00000000000000..cc5d6c59f9ca2f --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryDescriptorConfig.java @@ -0,0 +1,18 @@ +package io.quarkus.registry.config.json; + +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.config.RegistryDescriptorConfig; + +public class JsonRegistryDescriptorConfig implements RegistryDescriptorConfig { + + private ArtifactCoords artifact; + + @Override + public ArtifactCoords getArtifact() { + return artifact; + } + + public void setArtifact(ArtifactCoords artifact) { + this.artifact = artifact; + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryMavenConfig.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryMavenConfig.java new file mode 100644 index 00000000000000..5340eb3f91de36 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryMavenConfig.java @@ -0,0 +1,30 @@ +package io.quarkus.registry.config.json; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import io.quarkus.registry.config.RegistryMavenConfig; +import io.quarkus.registry.config.RegistryMavenRepoConfig; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class JsonRegistryMavenConfig implements RegistryMavenConfig { + + private RegistryMavenRepoConfig repo; + + @Override + @JsonDeserialize(as = JsonRegistryMavenRepoConfig.class) + public RegistryMavenRepoConfig getRepository() { + return repo; + } + + public void setRepository(RegistryMavenRepoConfig repo) { + this.repo = repo; + } + + @Override + public String toString() { + final StringBuilder buf = new StringBuilder(); + buf.append('['); + buf.append("repo=").append(repo); + return buf.append(']').toString(); + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryMavenRepoConfig.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryMavenRepoConfig.java new file mode 100644 index 00000000000000..7188ed1440e9f2 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryMavenRepoConfig.java @@ -0,0 +1,34 @@ +package io.quarkus.registry.config.json; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.quarkus.registry.config.RegistryMavenRepoConfig; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class JsonRegistryMavenRepoConfig implements RegistryMavenRepoConfig { + + private String id; + private String url; + + @Override + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + @Override + public String toString() { + return "[id=" + id + ", url=" + url + "]"; + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryNonPlatformExtensionsConfig.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryNonPlatformExtensionsConfig.java new file mode 100644 index 00000000000000..263022369f3b4b --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryNonPlatformExtensionsConfig.java @@ -0,0 +1,8 @@ +package io.quarkus.registry.config.json; + +import io.quarkus.registry.config.RegistryNonPlatformExtensionsConfig; + +public class JsonRegistryNonPlatformExtensionsConfig extends JsonRegistryArtifactConfig + implements RegistryNonPlatformExtensionsConfig { + +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryPlatformsConfig.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryPlatformsConfig.java new file mode 100644 index 00000000000000..190538bd298a5d --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryPlatformsConfig.java @@ -0,0 +1,17 @@ +package io.quarkus.registry.config.json; + +import io.quarkus.registry.config.RegistryPlatformsConfig; + +public class JsonRegistryPlatformsConfig extends JsonRegistryArtifactConfig implements RegistryPlatformsConfig { + + private Boolean extensionCatalogsIncluded; + + @Override + public Boolean getExtensionCatalogsIncluded() { + return extensionCatalogsIncluded; + } + + public void setExtensionCatalogsIncluded(Boolean extensionCatalogsIncluded) { + this.extensionCatalogsIncluded = extensionCatalogsIncluded; + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryQuarkusVersionsConfig.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryQuarkusVersionsConfig.java new file mode 100644 index 00000000000000..bfaf8b4fd976b4 --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/JsonRegistryQuarkusVersionsConfig.java @@ -0,0 +1,27 @@ +package io.quarkus.registry.config.json; + +import io.quarkus.registry.config.RegistryQuarkusVersionsConfig; + +public class JsonRegistryQuarkusVersionsConfig implements RegistryQuarkusVersionsConfig { + + private String recognizedVersionsExpression; + private boolean exclusiveProvider; + + @Override + public String getRecognizedVersionsExpression() { + return recognizedVersionsExpression; + } + + public void setRecognizedVersionsExpression(String recognizedVersionsExpression) { + this.recognizedVersionsExpression = recognizedVersionsExpression; + } + + @Override + public boolean isExclusiveProvider() { + return exclusiveProvider; + } + + public void setExclusiveProvider(boolean exclusiveProvider) { + this.exclusiveProvider = exclusiveProvider; + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/RegistriesConfigMapperHelper.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/RegistriesConfigMapperHelper.java new file mode 100644 index 00000000000000..e5bffc75f8265d --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/config/json/RegistriesConfigMapperHelper.java @@ -0,0 +1,145 @@ +package io.quarkus.registry.config.json; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.catalog.json.JsonArtifactCoordsMixin; +import io.quarkus.registry.config.RegistriesConfig; +import io.quarkus.registry.config.RegistriesConfigLocator; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class RegistriesConfigMapperHelper { + + private static ObjectMapper yamlMapper; + private static ObjectMapper jsonMapper; + + public static ObjectMapper yamlMapper() { + return yamlMapper == null ? yamlMapper = initMapper(new ObjectMapper(new YAMLFactory())) : yamlMapper; + } + + public static ObjectMapper jsonMapper() { + return jsonMapper == null ? jsonMapper = initMapper(new ObjectMapper()) : jsonMapper; + } + + private static ObjectMapper mapper(Path p) { + return p.getFileName().toString().endsWith(".json") ? jsonMapper() : yamlMapper(); + } + + public static ObjectMapper initMapper(ObjectMapper mapper) { + mapper.addMixIn(ArtifactCoords.class, JsonArtifactCoordsMixin.class); + mapper.enable(SerializationFeature.INDENT_OUTPUT); + mapper.setPropertyNamingStrategy(PropertyNamingStrategies.KEBAB_CASE); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + return mapper; + } + + public static void serialize(Object config, Path p) throws IOException { + if (!Files.exists(p.getParent())) { + Files.createDirectories(p.getParent()); + } + try (BufferedWriter writer = Files.newBufferedWriter(p)) { + mapper(p).writeValue(writer, config); + } + } + + public static void toJson(Object config, Writer writer) throws IOException { + jsonMapper().writeValue(writer, config); + } + + public static <T> T deserialize(Path p, Class<T> t) throws IOException { + if (!Files.exists(p)) { + throw new IllegalArgumentException("File " + p + " does not exist"); + } + try (BufferedReader reader = Files.newBufferedReader(p)) { + return mapper(p).readValue(reader, t); + } + } + + public static <T> T deserializeYaml(InputStream is, Class<T> t) throws IOException { + return yamlMapper().readValue(is, t); + } + + public static <T> T deserializeYaml(Reader reader, Class<T> t) throws IOException { + return yamlMapper().readValue(reader, t); + } + + public static void main(String[] args) throws Exception { + final Path p = serializeConfigSample(); + //logDeserialized(p); + logLoaded(p); + } + + private static Path serializeConfigSample() throws IOException { + final JsonRegistriesConfig resolver = new JsonRegistriesConfig(); + + JsonRegistryConfig qer = new JsonRegistryConfig("qer.acme.com"); + resolver.addRegistry(qer); + + qer = new JsonRegistryConfig("qer.acme.com"); + resolver.addRegistry(qer); + JsonRegistryMavenConfig mavenConfig = new JsonRegistryMavenConfig(); + JsonRegistryMavenRepoConfig mvnRepo = new JsonRegistryMavenRepoConfig(); + mvnRepo.setUrl("https://maven.acme.com"); + mavenConfig.setRepository(mvnRepo); + qer.setMaven(mavenConfig); + + qer = new JsonRegistryConfig("acme.com"); + resolver.addRegistry(qer); + JsonRegistryDescriptorConfig descr = new JsonRegistryDescriptorConfig(); + qer.setDescriptor(descr); + descr.setArtifact(new ArtifactCoords("com.acme", "registry-descriptor", null, "json", "0.1-SNAPSHOT")); + + mavenConfig = new JsonRegistryMavenConfig(); + mvnRepo = new JsonRegistryMavenRepoConfig(); + mvnRepo.setUrl("https://acme.com/maven"); + mavenConfig.setRepository(mvnRepo); + qer.setMaven(mavenConfig); + + qer = new JsonRegistryConfig("all"); + resolver.addRegistry(qer); + descr = new JsonRegistryDescriptorConfig(); + qer.setDescriptor(descr); + descr.setArtifact(new ArtifactCoords("org.acme", "registry-descriptor", null, "json", "0.1-SNAPSHOT")); + + mavenConfig = new JsonRegistryMavenConfig(); + mvnRepo = new JsonRegistryMavenRepoConfig(); + mvnRepo.setUrl("https://acme.com/rest/api/maven"); + mavenConfig.setRepository(mvnRepo); + qer.setMaven(mavenConfig); + + final Path p = Paths.get(System.getProperty("user.home")).resolve("test-qer-resolver-config.yaml"); + if (Files.exists(p)) { + Files.delete(p); + } + serialize(resolver, p); + return p; + } + + private static void logDeserialized(Path p) throws IOException { + JsonRegistriesConfig resolver = deserialize(p, JsonRegistriesConfig.class); + System.out.println("QER RESOLVER:"); + resolver.getRegistries().forEach(qer -> { + System.out.println(" - " + qer); + }); + } + + private static void logLoaded(Path p) throws IOException { + RegistriesConfig resolver = RegistriesConfigLocator.load(p); + System.out.println("QER RESOLVER:"); + resolver.getRegistries().forEach(qer -> { + System.out.println(" - " + qer); + }); + } + +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/util/GlobUtil.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/util/GlobUtil.java new file mode 100644 index 00000000000000..bb336dca6b33da --- /dev/null +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/util/GlobUtil.java @@ -0,0 +1,209 @@ +package io.quarkus.registry.util; + +import java.util.regex.Pattern; + +public class GlobUtil { + + private GlobUtil() { + } + + /** + * Transforms the given {@code glob} to a regular expression suitable for passing to + * {@link Pattern#compile(String)}. + * + * <h2>Glob syntax + * <h2> + * + * <table> + * <tr> + * <th>Construct</th> + * <th>Description</th> + * </tr> + * <tr> + * <td><code>*</code></td> + * <td>Matches a (possibly empty) sequence of characters that does not contain slash ({@code /})</td> + * </tr> + * <tr> + * <td><code>**</code></td> + * <td>Matches a (possibly empty) sequence of characters that may contain slash ({@code /})</td> + * </tr> + * <tr> + * <td><code>?</code></td> + * <td>Matches one character, but not slash</td> + * </tr> + * <tr> + * <td><code>[abc]</code></td> + * <td>Matches one character given in the bracket, but not slash</td> + * </tr> + * <tr> + * <td><code>[a-z]</code></td> + * <td>Matches one character from the range given in the bracket, but not slash</td> + * </tr> + * <tr> + * <td><code>[!abc]</code></td> + * <td>Matches one character not named in the bracket; does not match slash</td> + * </tr> + * <tr> + * <td><code>[a-z]</code></td> + * <td>Matches one character outside the range given in the bracket; does not match slash</td> + * </tr> + * <tr> + * <td><code>{one,two,three}</code></td> + * <td>Matches any of the alternating tokens separated by comma; the tokens may contain wildcards, nested + * alternations and ranges</td> + * </tr> + * <tr> + * <td><code>\</code></td> + * <td>The escape character</td> + * </tr> + * </table> + * + * @param glob the glob expression to transform + * @return a regular expression suitable for {@link Pattern} + * @throws IllegalStateException in case the {@code glob} is syntactically invalid + */ + public static String toRegexPattern(String glob) { + final int length = glob.length(); + final StringBuilder result = new StringBuilder(length + 4); + glob(glob, 0, length, null, result); + return result.toString(); + } + + private static int glob(String glob, int i, int length, String stopChars, StringBuilder result) { + while (i < length) { + char current = glob.charAt(i++); + switch (current) { + case '*': + if (i < length && glob.charAt(i) == '*') { + result.append(".*"); + i++; + } else { + result.append("[^/]*"); + } + break; + case '?': + result.append("[^/]"); + break; + case '[': + i = charClass(glob, i, length, result); + break; + case '{': + i = alternation(glob, i, length, result); + break; + case '\\': + i = unescape(glob, i, length, result, false); + break; + default: + if (stopChars != null && stopChars.indexOf(current) >= 0) { + i--; + return i; + } else { + escapeIfNeeded(current, result); + } + break; + } + } + return i; + } + + private static int alternation(String glob, int i, int length, StringBuilder result) { + result.append("(?:"); + while (i < length) { + char current = glob.charAt(i++); + switch (current) { + case '}': + result.append(')'); + return i; + case ',': + result.append('|'); + i = glob(glob, i, length, ",}", result); + break; + default: + i--; + i = glob(glob, i, length, ",}", result); + break; + } + } + throw new IllegalStateException(String.format("Missing } at the end of input in glob %s", glob)); + } + + private static int unescape(String glob, int i, int length, StringBuilder result, boolean charClass) { + if (i < length) { + final char current = glob.charAt(i++); + if (charClass) { + escapeCharClassIfNeeded(current, result); + } else { + escapeIfNeeded(current, result); + } + return i; + } else { + throw new IllegalStateException( + String.format("Incomplete escape sequence at the end of input in glob %s", glob)); + } + } + + private static int charClass(String glob, int i, int length, StringBuilder result) { + result.append("[[^/]&&["); + if (i < length && glob.charAt(i) == '!') { + i++; + result.append('^'); + } + while (i < length) { + char current = glob.charAt(i++); + switch (current) { + case ']': + result.append("]]"); + return i; + case '-': + result.append('-'); + break; + case '\\': + i = unescape(glob, i, length, result, true); + break; + default: + escapeCharClassIfNeeded(current, result); + break; + } + } + throw new IllegalStateException(String.format("Missing ] at the end of input in glob %s", glob)); + } + + private static void escapeIfNeeded(char current, StringBuilder result) { + switch (current) { + case '*': + case '?': + case '+': + case '.': + case '^': + case '$': + case '{': + case '[': + case ']': + case '|': + case '(': + case ')': + case '\\': + result.append('\\'); + break; + default: + break; + } + result.append(current); + } + + private static void escapeCharClassIfNeeded(char current, StringBuilder result) { + switch (current) { + case '^': + case '[': + case ']': + case '&': + case '-': + case '\\': + result.append('\\'); + break; + default: + break; + } + result.append(current); + } +} diff --git a/independent-projects/tools/registry-client/src/test/java/io/quarkus/devtools/registry/catalog/ExtensionPredicateTest.java b/independent-projects/tools/registry-client/src/test/java/io/quarkus/devtools/registry/catalog/ExtensionPredicateTest.java new file mode 100644 index 00000000000000..bb9d419c7e9e46 --- /dev/null +++ b/independent-projects/tools/registry-client/src/test/java/io/quarkus/devtools/registry/catalog/ExtensionPredicateTest.java @@ -0,0 +1,39 @@ +package io.quarkus.devtools.registry.catalog; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.catalog.ExtensionPredicate; +import io.quarkus.registry.catalog.json.JsonExtension; +import java.util.Arrays; +import org.junit.jupiter.api.Test; + +class ExtensionPredicateTest { + + @Test + void rejectUnlisted() { + ExtensionPredicate predicate = new ExtensionPredicate("foo"); + JsonExtension extension = new JsonExtension(); + extension.setArtifact(new ArtifactCoords("g", "a", null, "jar", "v")); + extension.setUnlisted(true); + assertThat(predicate).rejects(extension); + } + + @Test + void acceptKeywordInArtifactId() { + ExtensionPredicate predicate = new ExtensionPredicate("foo"); + JsonExtension extension = new JsonExtension(); + extension.setArtifact(new ArtifactCoords("g", "foo-bar", null, "jar", "1.0")); + assertThat(predicate).accepts(extension); + } + + @Test + void acceptKeywordInLabel() { + ExtensionPredicate predicate = new ExtensionPredicate("foo"); + JsonExtension extension = new JsonExtension(); + extension.setArtifact(new ArtifactCoords("g", "a", null, "jar", "1.0")); + extension.setKeywords(Arrays.asList("foo", "bar")); + assertThat(predicate).accepts(extension); + } + +} diff --git a/integration-tests/devtools/pom.xml b/integration-tests/devtools/pom.xml index 06ec6ff1fa4bc4..27aa22d17fb99e 100644 --- a/integration-tests/devtools/pom.xml +++ b/integration-tests/devtools/pom.xml @@ -23,7 +23,7 @@ <!-- test dependencies --> <dependency> <groupId>io.quarkus</groupId> - <artifactId>quarkus-platform-descriptor-resolver-json</artifactId> + <artifactId>quarkus-test-devtools</artifactId> <scope>test</scope> </dependency> <dependency> @@ -51,6 +51,27 @@ <build> <plugins> + <plugin> + <artifactId>maven-resources-plugin</artifactId> + <executions> + <execution> + <id>copy-resources</id> + <phase>process-test-resources</phase> + <goals> + <goal>testResources</goal> + </goals> + <configuration> + <outputDirectory>${basedir}/target/test-classes</outputDirectory> + <resources> + <resource> + <directory>${basedir}/src/test/resources</directory> + <filtering>true</filtering> + </resource> + </resources> + </configuration> + </execution> + </executions> + </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> diff --git a/integration-tests/devtools/src/test/java/io/quarkus/devtools/PlatformAwareTestBase.java b/integration-tests/devtools/src/test/java/io/quarkus/devtools/PlatformAwareTestBase.java index 60c229fab484c8..d08612fce384d1 100644 --- a/integration-tests/devtools/src/test/java/io/quarkus/devtools/PlatformAwareTestBase.java +++ b/integration-tests/devtools/src/test/java/io/quarkus/devtools/PlatformAwareTestBase.java @@ -1,27 +1,100 @@ package io.quarkus.devtools; +import static io.quarkus.devtools.codestarts.quarkus.QuarkusCodestartData.QuarkusDataKey.BOM_ARTIFACT_ID; +import static io.quarkus.devtools.codestarts.quarkus.QuarkusCodestartData.QuarkusDataKey.BOM_GROUP_ID; +import static io.quarkus.devtools.codestarts.quarkus.QuarkusCodestartData.QuarkusDataKey.BOM_VERSION; +import static io.quarkus.devtools.codestarts.quarkus.QuarkusCodestartData.QuarkusDataKey.JAVA_VERSION; +import static io.quarkus.devtools.codestarts.quarkus.QuarkusCodestartData.QuarkusDataKey.KOTLIN_VERSION; +import static io.quarkus.devtools.codestarts.quarkus.QuarkusCodestartData.QuarkusDataKey.MAVEN_COMPILER_PLUGIN_VERSION; +import static io.quarkus.devtools.codestarts.quarkus.QuarkusCodestartData.QuarkusDataKey.MAVEN_SUREFIRE_PLUGIN_VERSION; +import static io.quarkus.devtools.codestarts.quarkus.QuarkusCodestartData.QuarkusDataKey.PROJECT_ARTIFACT_ID; +import static io.quarkus.devtools.codestarts.quarkus.QuarkusCodestartData.QuarkusDataKey.PROJECT_GROUP_ID; +import static io.quarkus.devtools.codestarts.quarkus.QuarkusCodestartData.QuarkusDataKey.PROJECT_VERSION; +import static io.quarkus.devtools.codestarts.quarkus.QuarkusCodestartData.QuarkusDataKey.QUARKUS_GRADLE_PLUGIN_ID; +import static io.quarkus.devtools.codestarts.quarkus.QuarkusCodestartData.QuarkusDataKey.QUARKUS_GRADLE_PLUGIN_VERSION; +import static io.quarkus.devtools.codestarts.quarkus.QuarkusCodestartData.QuarkusDataKey.QUARKUS_MAVEN_PLUGIN_ARTIFACT_ID; +import static io.quarkus.devtools.codestarts.quarkus.QuarkusCodestartData.QuarkusDataKey.QUARKUS_MAVEN_PLUGIN_GROUP_ID; +import static io.quarkus.devtools.codestarts.quarkus.QuarkusCodestartData.QuarkusDataKey.QUARKUS_MAVEN_PLUGIN_VERSION; +import static io.quarkus.devtools.codestarts.quarkus.QuarkusCodestartData.QuarkusDataKey.QUARKUS_VERSION; +import static io.quarkus.devtools.codestarts.quarkus.QuarkusCodestartData.QuarkusDataKey.SCALA_MAVEN_PLUGIN_VERSION; +import static io.quarkus.devtools.codestarts.quarkus.QuarkusCodestartData.QuarkusDataKey.SCALA_VERSION; + +import java.util.HashMap; +import java.util.Map; import java.util.Properties; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.descriptor.resolver.json.QuarkusJsonPlatformDescriptorResolver; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; + +import io.quarkus.devtools.project.QuarkusProjectHelper; +import io.quarkus.devtools.test.DevToolsRegistryTestHelper; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.platform.descriptor.loader.json.ResourceLoader; +import io.quarkus.platform.tools.ToolsConstants; import io.quarkus.platform.tools.ToolsUtils; +import io.quarkus.registry.catalog.ExtensionCatalog; public class PlatformAwareTestBase { - private QuarkusPlatformDescriptor platformDescr; + private ExtensionCatalog catalog; private Properties quarkusProps; - protected QuarkusPlatformDescriptor getPlatformDescriptor() { - return platformDescr == null - ? platformDescr = QuarkusJsonPlatformDescriptorResolver.newInstance().resolveBundled() - : platformDescr; + @BeforeAll + static void enableDevToolsTestConfig() { + DevToolsRegistryTestHelper.enableDevToolsTestConfig(); + } + + @AfterAll + static void disableDevToolsTestConfig() { + DevToolsRegistryTestHelper.disableDevToolsTestConfig(); } - private Properties getQuarkusProperties() { - if (quarkusProps == null) { - quarkusProps = ToolsUtils.readQuarkusProperties(getPlatformDescriptor()); + protected ResourceLoader getCodestartsResourceLoader() { + return QuarkusProjectHelper.getResourceLoader(getExtensionsCatalog()); + } + + protected ExtensionCatalog getExtensionsCatalog() { + if (catalog == null) { + try { + catalog = QuarkusProjectHelper.getCatalogResolver().resolveExtensionCatalog(); + } catch (Exception e) { + throw new RuntimeException("Failed to resolve extensions catalog", e); + } } - return quarkusProps; + return catalog; + } + + protected Map<String, Object> getTestInputData(ExtensionCatalog catalog, Map<String, Object> override) { + + final ArtifactCoords bom = catalog.getBom(); + + final HashMap<String, Object> data = new HashMap<>(); + final Properties quarkusProp = getQuarkusProperties(); + data.put(PROJECT_GROUP_ID.key(), "org.test"); + data.put(PROJECT_ARTIFACT_ID.key(), "test-codestart"); + data.put(PROJECT_VERSION.key(), "1.0.0-codestart"); + data.put(BOM_GROUP_ID.key(), bom.getGroupId()); + data.put(BOM_ARTIFACT_ID.key(), bom.getArtifactId()); + data.put(BOM_VERSION.key(), bom.getVersion()); + data.put(QUARKUS_VERSION.key(), catalog.getQuarkusCoreVersion()); + data.put(QUARKUS_MAVEN_PLUGIN_GROUP_ID.key(), "io.quarkus"); + data.put(QUARKUS_MAVEN_PLUGIN_ARTIFACT_ID.key(), "quarkus-maven-plugin"); + data.put(QUARKUS_MAVEN_PLUGIN_VERSION.key(), catalog.getQuarkusCoreVersion()); + data.put(QUARKUS_GRADLE_PLUGIN_ID.key(), "io.quarkus"); + data.put(QUARKUS_GRADLE_PLUGIN_VERSION.key(), catalog.getQuarkusCoreVersion()); + data.put(KOTLIN_VERSION.key(), quarkusProp.getProperty(ToolsConstants.PROP_KOTLIN_VERSION)); + data.put(SCALA_VERSION.key(), quarkusProp.getProperty(ToolsConstants.PROP_SCALA_VERSION)); + data.put(SCALA_MAVEN_PLUGIN_VERSION.key(), quarkusProp.getProperty(ToolsConstants.PROP_SCALA_PLUGIN_VERSION)); + data.put(MAVEN_COMPILER_PLUGIN_VERSION.key(), quarkusProp.getProperty(ToolsConstants.PROP_COMPILER_PLUGIN_VERSION)); + data.put(MAVEN_SUREFIRE_PLUGIN_VERSION.key(), quarkusProp.getProperty(ToolsConstants.PROP_SUREFIRE_PLUGIN_VERSION)); + data.put(JAVA_VERSION.key(), "11"); + if (override != null) + data.putAll(override); + return data; + } + + protected Properties getQuarkusProperties() { + return quarkusProps == null ? quarkusProps = ToolsUtils.readQuarkusProperties(getExtensionsCatalog()) : quarkusProps; } protected String getMavenPluginGroupId() { @@ -40,15 +113,7 @@ protected String getQuarkusCoreVersion() { return ToolsUtils.getQuarkusCoreVersion(getQuarkusProperties()); } - protected String getBomGroupId() { - return getPlatformDescriptor().getBomGroupId(); - } - - protected String getBomArtifactId() { - return getPlatformDescriptor().getBomArtifactId(); - } - protected String getBomVersion() { - return getPlatformDescriptor().getBomVersion(); + return getQuarkusCoreVersion(); } } diff --git a/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/jbang/QuarkusJBangCodestartGenerationTest.java b/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/jbang/QuarkusJBangCodestartGenerationTest.java index 968d8ec261b642..9447516d1a5c56 100644 --- a/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/jbang/QuarkusJBangCodestartGenerationTest.java +++ b/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/jbang/QuarkusJBangCodestartGenerationTest.java @@ -54,7 +54,7 @@ void generatePicocliProject(TestInfo testInfo) throws Throwable { } private QuarkusJBangCodestartCatalog getCatalog() throws IOException { - return QuarkusJBangCodestartCatalog.fromQuarkusPlatformDescriptor(getPlatformDescriptor()); + return QuarkusJBangCodestartCatalog.fromResourceLoader(getCodestartsResourceLoader()); } } diff --git a/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartCatalogTest.java b/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartCatalogTest.java index 8c99da0d94e470..288e8164225fb9 100644 --- a/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartCatalogTest.java +++ b/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartCatalogTest.java @@ -162,7 +162,7 @@ void prepareProjectTestCommandMode() throws IOException { } private QuarkusCodestartCatalog getCatalog() throws IOException { - return QuarkusCodestartCatalog.fromQuarkusPlatformDescriptor(getPlatformDescriptor()); + return QuarkusCodestartCatalog.fromExtensionsCatalog(getExtensionsCatalog(), getCodestartsResourceLoader()); } } diff --git a/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartGenerationTest.java b/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartGenerationTest.java index f7f32ea29ec1e1..14ab10be5d6bc7 100644 --- a/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartGenerationTest.java +++ b/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartGenerationTest.java @@ -5,6 +5,7 @@ import static io.quarkus.devtools.testing.SnapshotTesting.checkContains; import static org.assertj.core.api.Assertions.assertThat; +import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collections; @@ -710,8 +711,8 @@ private void checkGradleWithKotlinDsl(Path projectDir) { .satisfies(checkContains("rootProject.name=\"test-codestart\"")); } - private QuarkusCodestartCatalog getCatalog() throws Throwable { - return QuarkusCodestartCatalog.fromQuarkusPlatformDescriptor(getPlatformDescriptor()); + private QuarkusCodestartCatalog getCatalog() throws IOException { + return QuarkusCodestartCatalog.fromExtensionsCatalog(getExtensionsCatalog(), getCodestartsResourceLoader()); } } diff --git a/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartRunIT.java b/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartRunIT.java index 8257ceb70a1df0..2b3f2c83a5863f 100644 --- a/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartRunIT.java +++ b/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/quarkus/QuarkusCodestartRunIT.java @@ -1,7 +1,5 @@ package io.quarkus.devtools.codestarts.quarkus; -import static io.quarkus.devtools.codestarts.quarkus.QuarkusCodestartData.QuarkusDataKey.*; -import static io.quarkus.platform.tools.ToolsUtils.readQuarkusProperties; import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; @@ -12,7 +10,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Properties; import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; @@ -35,9 +32,6 @@ import io.quarkus.devtools.project.BuildTool; import io.quarkus.devtools.testing.SnapshotTesting; import io.quarkus.devtools.testing.WrapperRunner; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.tools.ToolsConstants; -import io.quarkus.platform.tools.ToolsUtils; @TestInstance(TestInstance.Lifecycle.PER_CLASS) class QuarkusCodestartRunIT extends PlatformAwareTestBase { @@ -54,6 +48,10 @@ static void setUp() throws IOException { SnapshotTesting.deleteTestDirectory(testDirPath.toFile()); } + private Map<String, Object> getTestInputData(final Map<String, Object> override) { + return getTestInputData(getExtensionsCatalog(), override); + } + @Test public void testRunTogetherCodestartsJava() throws Exception { generateProjectRunTests("maven", "java", getRunTogetherExamples(), Collections.emptyMap()); @@ -172,41 +170,6 @@ private void generateProjectRunTests(String buildToolName, String language, List assertThat(result).isZero(); } - private Map<String, Object> getTestInputData() { - return getTestInputData(null); - } - - private Map<String, Object> getTestInputData(final Map<String, Object> override) { - return getTestInputData(getPlatformDescriptor(), override); - } - - private static Map<String, Object> getTestInputData(final QuarkusPlatformDescriptor descriptor, - final Map<String, Object> override) { - final HashMap<String, Object> data = new HashMap<>(); - final Properties quarkusProp = readQuarkusProperties(descriptor); - data.put(PROJECT_GROUP_ID.key(), "org.test"); - data.put(PROJECT_ARTIFACT_ID.key(), "test-codestart"); - data.put(PROJECT_VERSION.key(), "1.0.0-codestart"); - data.put(BOM_GROUP_ID.key(), descriptor.getBomGroupId()); - data.put(BOM_ARTIFACT_ID.key(), descriptor.getBomArtifactId()); - data.put(BOM_VERSION.key(), descriptor.getBomVersion()); - data.put(QUARKUS_VERSION.key(), descriptor.getQuarkusVersion()); - data.put(QUARKUS_MAVEN_PLUGIN_GROUP_ID.key(), ToolsUtils.getMavenPluginGroupId(quarkusProp)); - data.put(QUARKUS_MAVEN_PLUGIN_ARTIFACT_ID.key(), ToolsUtils.getMavenPluginArtifactId(quarkusProp)); - data.put(QUARKUS_MAVEN_PLUGIN_VERSION.key(), ToolsUtils.getMavenPluginVersion(quarkusProp)); - data.put(QUARKUS_GRADLE_PLUGIN_ID.key(), ToolsUtils.getMavenPluginGroupId(quarkusProp)); - data.put(QUARKUS_GRADLE_PLUGIN_VERSION.key(), ToolsUtils.getGradlePluginVersion(quarkusProp)); - data.put(JAVA_VERSION.key(), System.getProperty("java.specification.version")); - data.put(KOTLIN_VERSION.key(), quarkusProp.getProperty(ToolsConstants.PROP_KOTLIN_VERSION)); - data.put(SCALA_VERSION.key(), quarkusProp.getProperty(ToolsConstants.PROP_SCALA_VERSION)); - data.put(SCALA_MAVEN_PLUGIN_VERSION.key(), quarkusProp.getProperty(ToolsConstants.PROP_SCALA_PLUGIN_VERSION)); - data.put(MAVEN_COMPILER_PLUGIN_VERSION.key(), quarkusProp.getProperty(ToolsConstants.PROP_COMPILER_PLUGIN_VERSION)); - data.put(MAVEN_SUREFIRE_PLUGIN_VERSION.key(), quarkusProp.getProperty(ToolsConstants.PROP_SUREFIRE_PLUGIN_VERSION)); - if (override != null) - data.putAll(override); - return data; - } - private String genName(String buildtool, String language, List<String> codestarts) { String name = "project-" + buildtool + "-" + language; if (codestarts.isEmpty()) { @@ -220,7 +183,7 @@ private String genName(String buildtool, String language, List<String> codestart } private QuarkusCodestartCatalog getCatalog() throws IOException { - return QuarkusCodestartCatalog.fromQuarkusPlatformDescriptor(getPlatformDescriptor()); + return QuarkusCodestartCatalog.fromExtensionsCatalog(getExtensionsCatalog(), getCodestartsResourceLoader()); } private List<String> getRunTogetherExamples() throws IOException { diff --git a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/AbstractAddExtensionsTest.java b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/AbstractAddExtensionsTest.java index dede5b7c81e26b..61361d070d9ca6 100644 --- a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/AbstractAddExtensionsTest.java +++ b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/AbstractAddExtensionsTest.java @@ -14,10 +14,10 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import io.quarkus.dependencies.Extension; import io.quarkus.devtools.PlatformAwareTestBase; import io.quarkus.devtools.commands.data.QuarkusCommandException; import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; +import io.quarkus.registry.catalog.Extension; abstract class AbstractAddExtensionsTest<T> extends PlatformAwareTestBase { @@ -62,7 +62,7 @@ void testRegexpMatches() throws Exception { final T project = readProject(); getExtensionsWithArtifactContaining("smallrye") - .forEach(e -> hasDependency(project, e.getArtifactId())); + .forEach(e -> hasDependency(project, e.getArtifact().getArtifactId())); } @Test @@ -160,7 +160,7 @@ void doNotAddExtensionWhenMultipleMatchWithMultipleKeywords() throws Exception { final T project = readProject(); doesNotHaveDependency(project, "quarkus-agroal"); getExtensionsWithArtifactContaining("jdbc") - .forEach(e -> doesNotHaveDependency(project, e.getArtifactId())); + .forEach(e -> doesNotHaveDependency(project, e.getArtifact().getArtifactId())); } @Test @@ -172,7 +172,7 @@ void doesNotAddExtensionsWhenMultipleMatchWithOneKeyword() throws Exception { final T project = readProject(); getExtensionsWithArtifactContaining("jdbc") - .forEach(e -> doesNotHaveDependency(project, e.getArtifactId())); + .forEach(e -> doesNotHaveDependency(project, e.getArtifact().getArtifactId())); } @Test @@ -206,12 +206,12 @@ void testVertxWithDot() throws Exception { final T project = readProject(); getExtensionsWithArtifactContaining("vertx") - .forEach(e -> hasDependency(project, e.getArtifactId())); + .forEach(e -> hasDependency(project, e.getArtifact().getArtifactId())); } private Stream<Extension> getExtensionsWithArtifactContaining(String contains) { - return getPlatformDescriptor().getExtensions().stream() - .filter(e -> e.getArtifactId().contains(contains) && !e.isUnlisted()); + return getExtensionsCatalog().getExtensions().stream() + .filter(e -> e.getArtifact().getArtifactId().contains(contains) && !e.isUnlisted()); } private void hasDependency(T project, String artifactId) { diff --git a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/AddGradleExtensionsTest.java b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/AddGradleExtensionsTest.java index 0001b48d785c86..a9ba75e6c1043b 100644 --- a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/AddGradleExtensionsTest.java +++ b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/AddGradleExtensionsTest.java @@ -12,19 +12,20 @@ import io.quarkus.bootstrap.model.AppArtifactCoords; import io.quarkus.devtools.commands.data.QuarkusCommandException; import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; -import io.quarkus.devtools.project.BuildTool; import io.quarkus.devtools.project.QuarkusProject; +import io.quarkus.devtools.project.QuarkusProjectHelper; import io.quarkus.devtools.project.buildfile.AbstractGroovyGradleBuildFile; import io.quarkus.devtools.testing.SnapshotTesting; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.registry.RegistryResolutionException; +import io.quarkus.registry.catalog.ExtensionCatalog; class AddGradleExtensionsTest extends AbstractAddExtensionsTest<List<String>> { @Override protected List<String> createProject() throws IOException, QuarkusCommandException { SnapshotTesting.deleteTestDirectory(getProjectPath().toFile()); - new CreateProject(getProjectPath(), getPlatformDescriptor()) - .buildTool(BuildTool.GRADLE) + final QuarkusProject project = getQuarkusProject(); + new CreateProject(project) .groupId("org.acme") .artifactId("add-gradle-extension-test") .version("0.0.1-SNAPSHOT") @@ -57,16 +58,19 @@ private static String getBuildFileDependencyString(final String groupId, final S return " implementation '" + groupId + ":" + artifactId + versionPart + "'"; } - private QuarkusProject getQuarkusProject() { - final Path projectPath = getProjectPath(); - final QuarkusPlatformDescriptor platformDescriptor = getPlatformDescriptor(); - return QuarkusProject.of(projectPath, platformDescriptor, new TestingGradleBuildFile(projectPath, platformDescriptor)); + protected QuarkusProject getQuarkusProject() throws QuarkusCommandException { + try { + return QuarkusProjectHelper.getProject(getProjectPath(), + new TestingGradleBuildFile(getProjectPath(), getExtensionsCatalog())); + } catch (RegistryResolutionException e) { + throw new QuarkusCommandException("Failed to initialize Quarkus project", e); + } } static class TestingGradleBuildFile extends AbstractGroovyGradleBuildFile { - public TestingGradleBuildFile(Path projectDirPath, QuarkusPlatformDescriptor platformDescriptor) { - super(projectDirPath, platformDescriptor); + public TestingGradleBuildFile(Path projectDirPath, ExtensionCatalog catalog) { + super(projectDirPath, catalog); } @Override diff --git a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/AddMavenExtensionsTest.java b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/AddMavenExtensionsTest.java index df6b69e6cd4c3f..c1957fd01e9494 100644 --- a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/AddMavenExtensionsTest.java +++ b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/AddMavenExtensionsTest.java @@ -12,6 +12,7 @@ import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; import io.quarkus.devtools.project.BuildTool; import io.quarkus.devtools.project.QuarkusProject; +import io.quarkus.devtools.project.QuarkusProjectHelper; import io.quarkus.devtools.testing.SnapshotTesting; import io.quarkus.maven.utilities.MojoUtils; @@ -21,8 +22,8 @@ class AddMavenExtensionsTest extends AbstractAddExtensionsTest<Model> { protected Model createProject() throws IOException, QuarkusCommandException { final File pom = getProjectPath().resolve("pom.xml").toFile(); SnapshotTesting.deleteTestDirectory(getProjectPath().toFile()); - new CreateProject(getProjectPath(), getPlatformDescriptor()) - .buildTool(BuildTool.MAVEN) + final QuarkusProject project = getQuarkusProject(); + new CreateProject(project) .groupId("org.acme") .artifactId("add-maven-extension-test") .version("0.0.1-SNAPSHOT") @@ -51,6 +52,6 @@ protected long countDependencyOccurrences(final Model project, final String grou } private QuarkusProject getQuarkusProject() { - return QuarkusProject.maven(getProjectPath(), getPlatformDescriptor()); + return QuarkusProjectHelper.getProject(getProjectPath(), BuildTool.MAVEN); } } diff --git a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/CreateJBangProjectTest.java b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/CreateJBangProjectTest.java index 95cdd34a176f74..3fc2eb1602c0b6 100644 --- a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/CreateJBangProjectTest.java +++ b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/CreateJBangProjectTest.java @@ -14,6 +14,8 @@ import io.quarkus.devtools.PlatformAwareTestBase; import io.quarkus.devtools.commands.data.QuarkusCommandException; import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; +import io.quarkus.devtools.project.BuildTool; +import io.quarkus.devtools.project.QuarkusProjectHelper; import io.quarkus.devtools.testing.SnapshotTesting; public class CreateJBangProjectTest extends PlatformAwareTestBase { @@ -71,13 +73,12 @@ public void createRESTEasyWithExtensions() throws Exception { } private CreateJBangProject newCreateJBangProject(Path dir) { - return new CreateJBangProject(dir, getPlatformDescriptor()); + return new CreateJBangProject(QuarkusProjectHelper.getProject(dir, BuildTool.MAVEN)); } private void assertCreateJBangProject(CreateJBangProject createJBangProjectProject) throws QuarkusCommandException { - final QuarkusCommandOutcome result = createJBangProjectProject - .execute(); + final QuarkusCommandOutcome result = createJBangProjectProject.execute(); assertTrue(result.isSuccess()); } } diff --git a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/CreateProjectPlatformMetadataTest.java b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/CreateProjectPlatformMetadataTest.java index 54bd71dc2e66f8..bff47f1e244c9c 100644 --- a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/CreateProjectPlatformMetadataTest.java +++ b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/CreateProjectPlatformMetadataTest.java @@ -14,8 +14,6 @@ import org.assertj.core.util.Files; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; import com.fasterxml.jackson.databind.ObjectMapper; @@ -23,19 +21,20 @@ import io.quarkus.devtools.commands.data.QuarkusCommandException; import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; import io.quarkus.devtools.project.BuildTool; +import io.quarkus.devtools.project.QuarkusProject; +import io.quarkus.devtools.project.QuarkusProjectHelper; import io.quarkus.devtools.testing.SnapshotTesting; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.registry.catalog.ExtensionCatalog; public class CreateProjectPlatformMetadataTest extends PlatformAwareTestBase { private static final ObjectMapper JSON_MAPPER = new ObjectMapper(); - @ParameterizedTest - @ValueSource(booleans = { false, true }) - public void create(boolean legacyCodegen) throws Exception { + @Test + public void create() throws Exception { final File file = new File("target/meta-rest"); SnapshotTesting.deleteTestDirectory(file); - createProject(BuildTool.MAVEN, file, "io.quarkus", "basic-rest", "1.0.0-SNAPSHOT", legacyCodegen); + createProject(BuildTool.MAVEN, file, "io.quarkus", "basic-rest", "1.0.0-SNAPSHOT"); assertThat(file.toPath().resolve("pom.xml")) .exists() .satisfies(checkContains("<id>redhat</id>")) @@ -46,12 +45,11 @@ public void create(boolean legacyCodegen) throws Exception { .satisfies(checkContains("<pluginRepositories>")); } - @ParameterizedTest - @ValueSource(booleans = { false, true }) - public void createGradle(boolean legacyCodegen) throws Exception { + @Test + public void createGradle() throws Exception { final File file = new File("target/meta-rest-gradle"); SnapshotTesting.deleteTestDirectory(file); - createProject(BuildTool.GRADLE, file, "io.quarkus", "basic-rest", "1.0.0-SNAPSHOT", legacyCodegen); + createProject(BuildTool.GRADLE, file, "io.quarkus", "basic-rest", "1.0.0-SNAPSHOT"); assertThat(file.toPath().resolve("build.gradle")) .exists() .satisfies(checkContains("maven { url \"https://maven.repository.redhat.com\" }")); @@ -61,7 +59,7 @@ public void createGradle(boolean legacyCodegen) throws Exception { public void createGradleKotlin() throws Exception { final File file = new File("target/meta-rest-gradle-kts"); SnapshotTesting.deleteTestDirectory(file); - createProject(BuildTool.GRADLE_KOTLIN_DSL, file, "io.quarkus", "basic-rest", "1.0.0-SNAPSHOT", false); + createProject(BuildTool.GRADLE_KOTLIN_DSL, file, "io.quarkus", "basic-rest", "1.0.0-SNAPSHOT"); assertThat(file.toPath().resolve("build.gradle.kts")) .exists() .satisfies(checkContains("maven { url = uri(\"https://maven.repository.redhat.com\") }")); @@ -76,20 +74,17 @@ private Map<String, Object> getMetadata() throws java.io.IOException { Map.class); } - private void createProject(BuildTool buildTool, File file, String groupId, String artifactId, String version, - boolean legacyCodegen) + private void createProject(BuildTool buildTool, File file, String groupId, String artifactId, String version) throws QuarkusCommandException, IOException { - final QuarkusPlatformDescriptor platformDescriptor = getPlatformDescriptor(); - final QuarkusPlatformDescriptor spy = spy(platformDescriptor); + final ExtensionCatalog platformDescriptor = getExtensionsCatalog(); + final ExtensionCatalog spy = spy(platformDescriptor); when(spy.getMetadata()).thenReturn(getMetadata()); - final QuarkusCommandOutcome result = new CreateProject(file.toPath(), spy) - .buildTool(buildTool) + QuarkusProject project = QuarkusProjectHelper.getProject(file.toPath(), spy, buildTool); + final QuarkusCommandOutcome result = new CreateProject(project) .groupId(groupId) .artifactId(artifactId) - .legacyCodegen(legacyCodegen) .version(version) - .quarkusMavenPluginVersion("2.3.5") - .quarkusGradlePluginVersion("2.3.5-gradle") + .quarkusPluginVersion(buildTool == BuildTool.MAVEN ? "2.3.5" : "2.3.5-gradle") .execute(); assertTrue(result.isSuccess()); } diff --git a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/CreateProjectTest.java b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/CreateProjectTest.java index e6ecd54a693d6b..def60c953faa9e 100644 --- a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/CreateProjectTest.java +++ b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/CreateProjectTest.java @@ -4,7 +4,6 @@ import static io.quarkus.devtools.testing.SnapshotTesting.checkMatches; import static io.quarkus.platform.tools.ToolsConstants.PROP_COMPILER_PLUGIN_VERSION; import static io.quarkus.platform.tools.ToolsConstants.PROP_SUREFIRE_PLUGIN_VERSION; -import static io.quarkus.platform.tools.ToolsUtils.readQuarkusProperties; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -34,6 +33,8 @@ import io.quarkus.devtools.commands.data.QuarkusCommandException; import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; import io.quarkus.devtools.project.BuildTool; +import io.quarkus.devtools.project.QuarkusProject; +import io.quarkus.devtools.project.QuarkusProjectHelper; import io.quarkus.devtools.project.codegen.writer.FileProjectWriter; import io.quarkus.devtools.testing.SnapshotTesting; import io.quarkus.maven.utilities.MojoUtils; @@ -51,7 +52,7 @@ public void createRESTEasy() throws Exception { .className("org.acme.getting.started.GreetingResource") .resourcePath("/foo") .extensions(Collections.singleton("resteasy"))); - final Properties quarkusProp = readQuarkusProperties(getPlatformDescriptor()); + final Properties quarkusProp = getQuarkusProperties(); assertThat(projectDir.resolve(".gitignore")) .exists() .satisfies(checkMatches("(?s).*target/\\R.*")); @@ -142,8 +143,7 @@ public void createGradle() throws Exception { final File file = new File("target/create-resteasy-gradle"); final Path projectDir = file.toPath(); SnapshotTesting.deleteTestDirectory(file); - assertCreateProject(newCreateProject(projectDir) - .buildTool(BuildTool.GRADLE) + assertCreateProject(newCreateProject(projectDir, BuildTool.GRADLE) .groupId("io.foo") .packageName("my.project") .artifactId("resteasy-app") @@ -175,7 +175,11 @@ public void createGradle() throws Exception { } private CreateProject newCreateProject(Path dir) { - return new CreateProject(dir, getPlatformDescriptor()); + return newCreateProject(dir, BuildTool.MAVEN); + } + + private CreateProject newCreateProject(Path dir, BuildTool buildTool) { + return new CreateProject(QuarkusProjectHelper.getProject(dir, buildTool)); } @Test @@ -192,7 +196,8 @@ public void createOnTopOfExisting() throws Exception { final File pom = new File(testDir, "pom.xml"); MojoUtils.write(model, pom); assertThatExceptionOfType(QuarkusCommandException.class).isThrownBy(() -> { - new CreateProject(testDir.toPath(), getPlatformDescriptor()) + final QuarkusProject project = QuarkusProjectHelper.getProject(testDir.toPath(), BuildTool.MAVEN); + new CreateProject(project) .groupId("something.is") .artifactId("wrong") .version("1.0.0-SNAPSHOT") @@ -211,7 +216,8 @@ void createMultipleTimes() throws InterruptedException { List<Callable<Void>> collect = IntStream.range(0, 15).boxed().map(i -> (Callable<Void>) () -> { File tempDir = Files.createTempDirectory("test").toFile(); FileProjectWriter write = new FileProjectWriter(tempDir); - final QuarkusCommandOutcome result = new CreateProject(tempDir.toPath(), getPlatformDescriptor()) + final QuarkusProject project = QuarkusProjectHelper.getProject(tempDir.toPath(), BuildTool.MAVEN); + final QuarkusCommandOutcome result = new CreateProject(project) .groupId("org.acme") .artifactId("acme") .version("1.0.0-SNAPSHOT") @@ -230,8 +236,7 @@ void createMultipleTimes() throws InterruptedException { private void assertCreateProject(CreateProject createProject) throws QuarkusCommandException { final QuarkusCommandOutcome result = createProject - .quarkusMavenPluginVersion("2.3.5") - .quarkusGradlePluginVersion("2.3.5-gradle") + .quarkusPluginVersion("2.3.5") .execute(); assertTrue(result.isSuccess()); } diff --git a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/ListExtensionsTest.java b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/ListExtensionsTest.java index 37fb076e927c44..1b525211af0caf 100644 --- a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/ListExtensionsTest.java +++ b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/ListExtensionsTest.java @@ -26,7 +26,9 @@ import io.quarkus.devtools.PlatformAwareTestBase; import io.quarkus.devtools.commands.data.QuarkusCommandException; import io.quarkus.devtools.messagewriter.MessageWriter; +import io.quarkus.devtools.project.BuildTool; import io.quarkus.devtools.project.QuarkusProject; +import io.quarkus.devtools.project.QuarkusProjectHelper; import io.quarkus.devtools.testing.SnapshotTesting; import io.quarkus.maven.utilities.MojoUtils; import io.quarkus.maven.utilities.QuarkusDependencyPredicate; @@ -94,7 +96,6 @@ public void listWithoutBom() throws Exception { boolean resteasy = false; boolean panache = false; boolean hibernateValidator = false; - boolean checkGuideInLineAfter = false; for (String line : output.split("\r?\n")) { if (line.contains("agroal")) { assertTrue(line.startsWith("default"), "Agroal should list as being default: " + line); @@ -102,26 +103,23 @@ public void listWithoutBom() throws Exception { } else if (line.contains("quarkus-resteasy ")) { assertTrue(line.startsWith("custom*"), "RESTEasy should list as being custom*: " + line); assertTrue( - line.endsWith( + line.contains( String.format("%-15s", getMavenPluginVersion())), "RESTEasy should list as being custom*: " + line); resteasy = true; - checkGuideInLineAfter = true; + assertTrue( + line.endsWith( + String.format("%s", "https://quarkus.io/guides/rest-json")), + "RESTEasy should list as having an guide: " + line); } else if (line.contains("quarkus-hibernate-orm-panache ")) { assertTrue(line.startsWith("custom"), "Panache should list as being custom: " + line); assertTrue( - line.endsWith(String.format("%-25s", getMavenPluginVersion())), + line.contains(String.format("%-25s", getMavenPluginVersion())), "Panache should list as being custom*: " + line); panache = true; } else if (line.contains("hibernate-validator")) { assertTrue(line.startsWith(" "), "Hibernate Validator should not list as anything: " + line); hibernateValidator = true; - } else if (checkGuideInLineAfter) { - checkGuideInLineAfter = false; - assertTrue( - line.endsWith( - String.format("%s", "https://quarkus.io/guides/rest-json")), - "RESTEasy should list as having an guide: " + line); } } @@ -156,7 +154,6 @@ public void searchRest() throws Exception { final QuarkusProject quarkusProject = createNewProject(new File("target/list-extensions-test", "pom.xml")); addExtensions(quarkusProject, "commons-io:commons-io:2.5", "Agroal"); - final PrintStream out = System.out; final ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (final PrintStream printStream = new PrintStream(baos, false, "UTF-8")) { new ListExtensions(quarkusProject, MessageWriter.info(printStream)) @@ -172,10 +169,10 @@ public void searchRest() throws Exception { @Test void testListExtensionsWithoutAPomFile() throws Exception { final Path tempDirectory = Files.createTempDirectory("proj"); - final QuarkusProject project = QuarkusProject.maven(tempDirectory, getPlatformDescriptor()); + final QuarkusProject project = QuarkusProjectHelper.getProject(tempDirectory, BuildTool.MAVEN); final Map<AppArtifactKey, AppArtifactCoords> installed = readByKey(project); assertTrue(installed.isEmpty()); - assertFalse(project.getPlatformDescriptor().getExtensions().isEmpty()); + assertFalse(project.getExtensionsCatalog().getExtensions().isEmpty()); final ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (final PrintStream printStream = new PrintStream(baos, false, "UTF-8")) { @@ -194,12 +191,13 @@ private void addExtensions(QuarkusProject quarkusProject, String... extensions) private QuarkusProject createNewProject(final File pom) throws IOException, QuarkusCommandException { SnapshotTesting.deleteTestDirectory(pom.getParentFile()); final Path projectDirPath = pom.getParentFile().toPath(); - new CreateProject(projectDirPath, getPlatformDescriptor()) + final QuarkusProject project = QuarkusProjectHelper.getProject(projectDirPath, BuildTool.MAVEN); + new CreateProject(project) .groupId("org.acme") .artifactId("add-extension-test") .version("0.0.1-SNAPSHOT") .execute(); - return QuarkusProject.maven(projectDirPath, getPlatformDescriptor()); + return project; } private static Map<AppArtifactKey, AppArtifactCoords> readByKey(QuarkusProject project) throws IOException { diff --git a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/RemoveGradleExtensionsTest.java b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/RemoveGradleExtensionsTest.java index 9d280334420556..84f66d11ad1902 100644 --- a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/RemoveGradleExtensionsTest.java +++ b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/RemoveGradleExtensionsTest.java @@ -2,18 +2,18 @@ import java.io.IOException; import java.nio.file.Files; -import java.nio.file.Path; import java.util.HashSet; import java.util.List; import org.junit.jupiter.api.Disabled; +import io.quarkus.devtools.commands.AddGradleExtensionsTest.TestingGradleBuildFile; import io.quarkus.devtools.commands.data.QuarkusCommandException; import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; -import io.quarkus.devtools.project.BuildTool; import io.quarkus.devtools.project.QuarkusProject; +import io.quarkus.devtools.project.QuarkusProjectHelper; import io.quarkus.devtools.testing.SnapshotTesting; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; +import io.quarkus.registry.RegistryResolutionException; class RemoveGradleExtensionsTest extends AbstractRemoveExtensionsTest<List<String>> { @@ -25,8 +25,7 @@ void addExtensionTwiceInTwoBatches() throws IOException { @Override protected List<String> createProject() throws IOException, QuarkusCommandException { SnapshotTesting.deleteTestDirectory(getProjectPath().toFile()); - new CreateProject(getProjectPath(), getPlatformDescriptor()) - .buildTool(BuildTool.GRADLE) + new CreateProject(getQuarkusProject()) .groupId("org.acme") .artifactId("add-gradle-extension-test") .version("0.0.1-SNAPSHOT") @@ -62,11 +61,13 @@ protected long countDependencyOccurrences(final List<String> buildFile, final St .count(); } - private QuarkusProject getQuarkusProject() { - final Path projectPath = getProjectPath(); - final QuarkusPlatformDescriptor platformDescriptor = getPlatformDescriptor(); - return QuarkusProject.of(projectPath, platformDescriptor, - new AddGradleExtensionsTest.TestingGradleBuildFile(projectPath, platformDescriptor)); + protected QuarkusProject getQuarkusProject() throws QuarkusCommandException { + try { + return QuarkusProjectHelper.getProject(getProjectPath(), + new TestingGradleBuildFile(getProjectPath(), getExtensionsCatalog())); + } catch (RegistryResolutionException e) { + throw new QuarkusCommandException("Failed to initialize Quarkus project", e); + } } private static String getBuildFileDependencyString(final String groupId, final String artifactId, final String version) { diff --git a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/RemoveMavenExtensionsTest.java b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/RemoveMavenExtensionsTest.java index 3b48d948a3ad4c..6fa2ecf1864c5f 100644 --- a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/RemoveMavenExtensionsTest.java +++ b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/RemoveMavenExtensionsTest.java @@ -10,7 +10,9 @@ import io.quarkus.devtools.commands.data.QuarkusCommandException; import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; +import io.quarkus.devtools.project.BuildTool; import io.quarkus.devtools.project.QuarkusProject; +import io.quarkus.devtools.project.QuarkusProjectHelper; import io.quarkus.devtools.testing.SnapshotTesting; import io.quarkus.maven.utilities.MojoUtils; @@ -20,7 +22,8 @@ class RemoveMavenExtensionsTest extends AbstractRemoveExtensionsTest<Model> { protected Model createProject() throws IOException, QuarkusCommandException { final File pom = getProjectPath().resolve("pom.xml").toFile(); SnapshotTesting.deleteTestDirectory(getProjectPath().toFile()); - new CreateProject(getProjectPath(), getPlatformDescriptor()) + final QuarkusProject project = getQuarkusProject(); + new CreateProject(project) .groupId("org.acme") .artifactId("add-maven-extension-test") .version("0.0.1-SNAPSHOT") @@ -56,6 +59,6 @@ protected long countDependencyOccurrences(final Model project, final String grou } private QuarkusProject getQuarkusProject() { - return QuarkusProject.maven(getProjectPath(), getPlatformDescriptor()); + return QuarkusProjectHelper.getProject(getProjectPath(), BuildTool.MAVEN); } } diff --git a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/handlers/QuarkusCommandHandlersTest.java b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/handlers/QuarkusCommandHandlersTest.java index 2b6f9b51bcabe7..ba043654d46495 100644 --- a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/handlers/QuarkusCommandHandlersTest.java +++ b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/handlers/QuarkusCommandHandlersTest.java @@ -3,28 +3,34 @@ import static io.quarkus.devtools.commands.handlers.QuarkusCommandHandlers.select; import static java.util.Arrays.asList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import io.quarkus.dependencies.Extension; import io.quarkus.devtools.commands.data.SelectionResult; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.catalog.Extension; +import io.quarkus.registry.catalog.json.JsonExtension; class QuarkusCommandHandlersTest { @Test void testMultiMatchByLabels() { - Extension e1 = new Extension("org.acme", "e1", "1.0") - .setName("some extension 1") - .setKeywords(new String[] { "foo", "bar" }); - Extension e2 = new Extension("org.acme", "e2", "1.0") - .setName("some extension 2") - .setKeywords(new String[] { "foo", "bar", "baz" }); - Extension e3 = new Extension("org.acme", "e3", "1.0") - .setName("unrelated") - .setKeywords(new String[] { "bar" }); + JsonExtension e1 = new JsonExtension(); + e1.setArtifact(new ArtifactCoords("org.acme", "e1", "1.0")); + e1.setName("some extension 1"); + e1.setKeywords(Arrays.asList("foo", "bar")); + JsonExtension e2 = new JsonExtension(); + e2.setArtifact(new ArtifactCoords("org.acme", "e2", "1.0")); + e2.setName("some extension 2"); + e2.setKeywords(Arrays.asList("foo", "bar", "baz")); + JsonExtension e3 = new JsonExtension(); + e3.setArtifact(new ArtifactCoords("org.acme", "e3", "1.0")); + e3.setName("unrelated"); + e3.setKeywords(Arrays.asList("bar")); List<Extension> extensions = asList(e1, e2, e3); Collections.shuffle(extensions); @@ -39,12 +45,14 @@ void testMultiMatchByLabels() { @Test void testThatSingleLabelMatchIsNotAMatch() { - Extension e1 = new Extension("org.acme", "e1", "1.0") - .setName("e1") - .setKeywords(new String[] { "foo", "bar" }); - Extension e2 = new Extension("org.acme", "e2", "1.0") - .setName("e2") - .setKeywords(new String[] { "bar", "baz" }); + JsonExtension e1 = new JsonExtension(); + e1.setArtifact(new ArtifactCoords("org.acme", "e1", "1.0")); + e1.setName("e1"); + e1.setKeywords(Arrays.asList("foo", "bar")); + JsonExtension e2 = new JsonExtension(); + e2.setArtifact(new ArtifactCoords("org.acme", "e2", "1.0")); + e2.setName("e2"); + e2.setKeywords(Arrays.asList("bar", "baz")); List<Extension> extensions = asList(e1, e2); Collections.shuffle(extensions); @@ -55,20 +63,23 @@ void testThatSingleLabelMatchIsNotAMatch() { @Test void testMultiMatchByArtifactIdsAndNames() { - Extension e1 = new Extension("org.acme", "e1", "1.0") - .setName("foo") - .setKeywords(new String[] { "foo", "bar" }); - Extension e2 = new Extension("org.acme", "quarkus-foo", "1.0") - .setName("some foo bar") - .setKeywords(new String[] { "foo", "bar", "baz" }); - Extension e3 = new Extension("org.acme", "e3", "1.0") - .setName("unrelated") - .setKeywords(new String[] { "foo" }); + JsonExtension e1 = new JsonExtension(); + e1.setArtifact(new ArtifactCoords("org.acme", "e1", "1.0")); + e1.setName("foo"); + e1.setKeywords(asList("foo", "bar")); + JsonExtension e2 = new JsonExtension(); + e2.setArtifact(new ArtifactCoords("org.acme", "quarkus-foo", "1.0")); + e2.setName("some foo bar"); + e2.setKeywords(asList("foo", "bar", "baz")); + JsonExtension e3 = new JsonExtension(); + e3.setArtifact(new ArtifactCoords("org.acme", "e3", "1.0")); + e3.setName("unrelated"); + e3.setKeywords(asList("foo")); List<Extension> extensions = asList(e1, e2, e3); Collections.shuffle(extensions); SelectionResult matches = select("foo", extensions, false); - Assertions.assertFalse(matches.matches()); + Assertions.assertFalse(matches.matches(), " " + matches.getExtensions().size()); Assertions.assertEquals(2, matches.getExtensions().size()); matches = select("foo", extensions, true); @@ -79,16 +90,19 @@ void testMultiMatchByArtifactIdsAndNames() { @Test void testShortNameSelection() { - Extension e1 = new Extension("org.acme", "some-complex-seo-unaware-artifactid", "1.0") - .setName("some complex seo unaware name") - .setShortName("foo") - .setKeywords(new String[] { "foo", "bar" }); - Extension e2 = new Extension("org.acme", "some-foo-bar", "1.0") - .setName("some foo bar") - .setKeywords(new String[] { "foo", "bar", "baz" }); - Extension e3 = new Extension("org.acme", "unrelated", "1.0") - .setName("unrelated") - .setKeywords(new String[] { "foo" }); + JsonExtension e1 = new JsonExtension(); + e1.setArtifact(new ArtifactCoords("org.acme", "some-complex-seo-unaware-artifactid", "1.0")); + e1.setName("some complex seo unaware name"); + e1.setShortName("foo"); + e1.setKeywords(asList("foo", "bar")); + JsonExtension e2 = new JsonExtension(); + e2.setArtifact(new ArtifactCoords("org.acme", "some-foo-bar", "1.0")); + e2.setName("some foo bar"); + e2.setKeywords(asList("foo", "bar", "baz")); + JsonExtension e3 = new JsonExtension(); + e3.setArtifact(new ArtifactCoords("org.acme", "unrelated", "1.0")); + e3.setName("unrelated"); + e3.setKeywords(asList("foo")); List<Extension> extensions = asList(e1, e2, e3); Collections.shuffle(extensions); @@ -97,43 +111,52 @@ void testShortNameSelection() { Assertions.assertEquals(1, matches.getExtensions().size()); Assertions.assertTrue(matches.iterator().hasNext()); Assertions - .assertTrue(matches.iterator().next().getArtifactId().equalsIgnoreCase("some-complex-seo-unaware-artifactid")); + .assertTrue(matches.iterator().next().getArtifact().getArtifactId() + .equalsIgnoreCase("some-complex-seo-unaware-artifactid")); } @Test void testArtifactIdSelectionWithQuarkusPrefix() { - Extension e1 = new Extension("org.acme", "quarkus-foo", "1.0") - .setName("some complex seo unaware name") - .setShortName("foo") - .setKeywords(new String[] { "foo", "bar" }); - Extension e2 = new Extension("org.acme", "quarkus-foo-bar", "1.0") - .setName("some foo bar") - .setKeywords(new String[] { "foo", "bar", "baz" }); - Extension e3 = new Extension("org.acme", "quarkus-unrelated", "1.0") - .setName("unrelated") - .setKeywords(new String[] { "foo" }); + JsonExtension e1 = new JsonExtension(); + e1.setArtifact(new ArtifactCoords("org.acme", "quarkus-foo", "1.0")); + e1.setName("some complex seo unaware name"); + e1.setShortName("foo"); + e1.setKeywords(asList("foo", "bar")); + JsonExtension e2 = new JsonExtension(); + e2.setArtifact(new ArtifactCoords("org.acme", "quarkus-foo-bar", "1.0")); + e2.setName("some foo bar"); + e2.setKeywords(asList("foo", "bar", "baz")); + JsonExtension e3 = new JsonExtension(); + e3.setArtifact(new ArtifactCoords("org.acme", "quarkus-unrelated", "1.0")); + e3.setName("unrelated"); + e3.setKeywords(asList("foo")); List<Extension> extensions = asList(e1, e2, e3); Collections.shuffle(extensions); SelectionResult matches = select("foo", extensions, false); Assertions.assertEquals(1, matches.getExtensions().size()); Assertions.assertTrue(matches.iterator().hasNext()); - Assertions.assertTrue(matches.iterator().next().getArtifactId().equalsIgnoreCase("quarkus-foo")); + Assertions.assertTrue(matches.iterator().next().getArtifact().getArtifactId().equalsIgnoreCase("quarkus-foo")); } @Test void testListedVsUnlisted() { - Extension e1 = new Extension("org.acme", "quarkus-foo-unlisted", "1.0") - .setName("some complex seo unaware name") - .setShortName("foo") - .setKeywords(new String[] { "foo", "bar" }).addMetadata("unlisted", "true"); - - Extension e2 = new Extension("org.acme", "quarkus-foo-bar", "1.0") - .setName("some foo bar") - .setKeywords(new String[] { "foo", "bar", "baz" }).addMetadata("unlisted", "false"); - Extension e3 = new Extension("org.acme", "quarkus-foo-baz", "1.0") - .setName("unrelated") - .setKeywords(new String[] { "foo" }); + JsonExtension e1 = new JsonExtension(); + e1.setArtifact(new ArtifactCoords("org.acme", "quarkus-foo-unlisted", "1.0")); + e1.setName("some complex seo unaware name"); + e1.setShortName("foo"); + e1.setKeywords(asList("foo", "bar")); + e1.addMetadata("unlisted", "true"); + + JsonExtension e2 = new JsonExtension(); + e2.setArtifact(new ArtifactCoords("org.acme", "quarkus-foo-bar", "1.0")); + e2.setName("some foo bar"); + e2.setKeywords(asList("foo", "bar", "baz")); + e2.addMetadata("unlisted", "false"); + JsonExtension e3 = new JsonExtension(); + e3.setArtifact(new ArtifactCoords("org.acme", "quarkus-foo-baz", "1.0")); + e3.setName("unrelated"); + e3.setKeywords(asList("foo")); List<Extension> extensions = asList(e1, e2, e3); Collections.shuffle(extensions); diff --git a/integration-tests/devtools/src/test/java/io/quarkus/devtools/project/codegen/rest/BasicRestProjectGeneratorTest.java b/integration-tests/devtools/src/test/java/io/quarkus/devtools/project/codegen/rest/BasicRestProjectGeneratorTest.java deleted file mode 100644 index b870251971fc17..00000000000000 --- a/integration-tests/devtools/src/test/java/io/quarkus/devtools/project/codegen/rest/BasicRestProjectGeneratorTest.java +++ /dev/null @@ -1,148 +0,0 @@ -package io.quarkus.devtools.project.codegen.rest; - -import static io.quarkus.devtools.project.codegen.ProjectGenerator.BOM_VERSION; -import static io.quarkus.devtools.project.codegen.ProjectGenerator.CLASS_NAME; -import static io.quarkus.devtools.project.codegen.ProjectGenerator.IS_SPRING; -import static io.quarkus.devtools.project.codegen.ProjectGenerator.PACKAGE_NAME; -import static io.quarkus.devtools.project.codegen.ProjectGenerator.PROJECT_ARTIFACT_ID; -import static io.quarkus.devtools.project.codegen.ProjectGenerator.PROJECT_GROUP_ID; -import static io.quarkus.devtools.project.codegen.ProjectGenerator.PROJECT_VERSION; -import static io.quarkus.devtools.project.codegen.ProjectGenerator.SOURCE_TYPE; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.Timeout; - -import io.quarkus.bootstrap.util.IoUtils; -import io.quarkus.devtools.PlatformAwareTestBase; -import io.quarkus.devtools.commands.data.QuarkusCommandInvocation; -import io.quarkus.devtools.project.QuarkusProject; -import io.quarkus.devtools.project.codegen.SourceType; -import io.quarkus.devtools.project.codegen.writer.ProjectWriter; -import io.quarkus.maven.utilities.MojoUtils; - -class BasicRestProjectGeneratorTest extends PlatformAwareTestBase { - - private final Map<String, Object> basicProjectContext = new HashMap<>(); - - @BeforeEach - void setUp() { - basicProjectContext.put(PROJECT_GROUP_ID, "org.example"); - basicProjectContext.put(PROJECT_ARTIFACT_ID, "quarkus-app"); - basicProjectContext.put(PROJECT_VERSION, "0.0.1-SNAPSHOT"); - basicProjectContext.put(BOM_VERSION, getBomVersion()); - basicProjectContext.put(PACKAGE_NAME, "org.example"); - basicProjectContext.put(CLASS_NAME, "ExampleResource"); - basicProjectContext.put("path", "/hello"); - basicProjectContext.put(SOURCE_TYPE, SourceType.JAVA); - } - - @Test - @Timeout(5) - @DisplayName("Should generate correctly multiple times in parallel with multiple threads") - void generateMultipleTimes() throws InterruptedException { - final ExecutorService executorService = Executors.newFixedThreadPool(4); - final CountDownLatch latch = new CountDownLatch(20); - final BasicRestProjectGenerator basicRestProjectGenerator = new BasicRestProjectGenerator(); - List<Callable<Void>> collect = IntStream.range(0, 20).boxed().map(i -> (Callable<Void>) () -> { - final Path path = Files.createTempDirectory("test"); - try { - basicRestProjectGenerator.generate(createQuarkusCommandInvocation(path)); - } finally { - IoUtils.recursiveDelete(path); - } - latch.countDown(); - return null; - }).collect(Collectors.toList()); - executorService.invokeAll(collect); - latch.await(); - } - - @Test - @DisplayName("Should generate project files with basic context") - void generateFilesWithJaxRsResource() throws Exception { - final ProjectWriter mockWriter = mock(ProjectWriter.class); - final Path mockProjectPath = mock(Path.class); - final BasicRestProjectGenerator basicRestProjectGenerator = new BasicRestProjectGenerator(); - - when(mockWriter.mkdirs(anyString())).thenAnswer(invocationOnMock -> invocationOnMock.getArgument(0, String.class)); - - basicRestProjectGenerator.generate(mockWriter, - createQuarkusCommandInvocation(mockProjectPath)); - - verify(mockWriter, times(10)).mkdirs(anyString()); - verify(mockWriter, times(3)).mkdirs(""); - verify(mockWriter, times(1)).mkdirs("src/main/java"); - verify(mockWriter, times(1)).mkdirs("src/main/java/org/example"); - verify(mockWriter, times(1)).mkdirs("src/test/java"); - verify(mockWriter, times(1)).mkdirs("src/test/java/org/example"); - verify(mockWriter, times(1)).mkdirs("src/main/resources"); - verify(mockWriter, times(1)).mkdirs("src/main/resources/META-INF/resources"); - verify(mockWriter, times(1)).mkdirs("src/main/docker"); - - verify(mockWriter, times(12)).write(anyString(), anyString()); - verify(mockWriter, times(1)).write(eq("pom.xml"), - argThat(argument -> argument.contains("<groupId>org.example</groupId>") - && argument.contains("<artifactId>quarkus-app</artifactId") - && argument.contains("<version>0.0.1-SNAPSHOT</version>") - && argument.contains( - "<" + MojoUtils.TEMPLATE_PROPERTY_QUARKUS_PLATFORM_VERSION_NAME + ">" + getQuarkusCoreVersion() - + "</" + MojoUtils.TEMPLATE_PROPERTY_QUARKUS_PLATFORM_VERSION_NAME + ">"))); - verify(mockWriter, times(1)).write(eq("src/main/java/org/example/ExampleResource.java"), - argThat(argument -> argument.contains("@Path(\"/hello\")"))); - verify(mockWriter, times(1)).write(eq("src/test/java/org/example/ExampleResourceTest.java"), anyString()); - verify(mockWriter, times(1)).write(eq("src/test/java/org/example/NativeExampleResourceIT.java"), anyString()); - verify(mockWriter, times(1)).write(eq("src/main/resources/application.properties"), anyString()); - verify(mockWriter, times(1)).write(eq("src/main/resources/META-INF/resources/index.html"), anyString()); - verify(mockWriter, times(1)).write(eq("src/main/docker/Dockerfile.native"), anyString()); - verify(mockWriter, times(1)).write(eq("src/main/docker/Dockerfile.jvm"), anyString()); - verify(mockWriter, times(1)).write(eq("src/main/docker/Dockerfile.legacy-jar"), anyString()); - verify(mockWriter, times(1)).write(eq(".dockerignore"), anyString()); - } - - @Test - @DisplayName("Should generate project files with basic spring web context") - void generateFilesWithSpringControllerResource() throws Exception { - final ProjectWriter mockWriter = mock(ProjectWriter.class); - final Path mockProjectPath = mock(Path.class); - final BasicRestProjectGenerator basicRestProjectGenerator = new BasicRestProjectGenerator(); - - when(mockWriter.mkdirs(anyString())).thenAnswer(invocationOnMock -> invocationOnMock.getArgument(0, String.class)); - - QuarkusCommandInvocation springContext = createQuarkusCommandInvocation(mockProjectPath); - springContext.setValue(IS_SPRING, Boolean.TRUE); - basicRestProjectGenerator.generate(mockWriter, springContext); - - verify(mockWriter, times(1)).write(eq("src/main/java/org/example/ExampleResource.java"), - argThat(argument -> argument.contains("@RequestMapping(\"/hello\")"))); - verify(mockWriter, times(1)).write(eq("src/main/java/org/example/ExampleResource.java"), - argThat(argument -> argument.contains("@RestController"))); - - } - - private QuarkusCommandInvocation createQuarkusCommandInvocation(Path projectPath) { - return new QuarkusCommandInvocation(QuarkusProject.maven(projectPath, getPlatformDescriptor()), - basicProjectContext); - } - -} diff --git a/integration-tests/devtools/src/test/java/io/quarkus/devtools/project/compress/QuarkusProjectCompressTest.java b/integration-tests/devtools/src/test/java/io/quarkus/devtools/project/compress/QuarkusProjectCompressTest.java index 883e755e4be0a5..12fdb6f4fb4067 100644 --- a/integration-tests/devtools/src/test/java/io/quarkus/devtools/project/compress/QuarkusProjectCompressTest.java +++ b/integration-tests/devtools/src/test/java/io/quarkus/devtools/project/compress/QuarkusProjectCompressTest.java @@ -22,6 +22,9 @@ import io.quarkus.devtools.commands.CreateProject; import io.quarkus.devtools.commands.data.QuarkusCommandException; import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; +import io.quarkus.devtools.project.BuildTool; +import io.quarkus.devtools.project.QuarkusProject; +import io.quarkus.devtools.project.QuarkusProjectHelper; import io.quarkus.devtools.testing.SnapshotTesting; class QuarkusProjectCompressTest extends PlatformAwareTestBase { @@ -82,7 +85,8 @@ private void checkUnzipped(Path projectPath, Path unzipProject) throws IOExcepti private Path createProject(Path testDir) throws QuarkusCommandException, IOException { final Path projectPath = testDir.resolve("project"); - final QuarkusCommandOutcome result = new CreateProject(projectPath, getPlatformDescriptor()) + final QuarkusProject project = QuarkusProjectHelper.getProject(projectPath, BuildTool.MAVEN); + final QuarkusCommandOutcome result = new CreateProject(project) .groupId("org.acme") .artifactId("basic-rest") .version("1.0.0-SNAPSHOT") diff --git a/integration-tests/devtools/src/test/resources/platform-metadata.json b/integration-tests/devtools/src/test/resources/platform-metadata.json index f392cfc6d3e338..49c0eb3f4dc3ac 100644 --- a/integration-tests/devtools/src/test/resources/platform-metadata.json +++ b/integration-tests/devtools/src/test/resources/platform-metadata.json @@ -24,5 +24,29 @@ "url": "https://maven.repository.redhat.com" } ] - } + }, + "project": { + "properties": { + "doc-root": "https://quarkus.io", + "rest-assured-version": "${rest-assured.version}", + "compiler-plugin-version": "${compiler-plugin.version}", + "surefire-plugin-version": "${version.surefire.plugin}", + "kotlin-version": "${kotlin.version}", + "scala-version": "${scala.version}", + "scala-plugin-version": "${scala-plugin.version}", + "quarkus-core-version": "${project.version}", + "maven-plugin-groupId": "${project.groupId}", + "maven-plugin-artifactId": "quarkus-maven-plugin", + "maven-plugin-version": "${project.version}", + "gradle-plugin-id": "io.quarkus", + "gradle-plugin-version": "${project.version}", + "supported-maven-versions": "${supported-maven-versions}", + "proposed-maven-version": "${proposed-maven-version}", + "maven-wrapper-version": "${maven-wrapper.version}", + "gradle-wrapper-version": "${gradle-wrapper.version}" + } + }, + "codestarts-artifacts": [ + "${project.groupId}:quarkus-platform-descriptor-json::jar:${project.version}" + ] } \ No newline at end of file diff --git a/integration-tests/gradle/build.gradle b/integration-tests/gradle/build.gradle index ab1a01a881e7ed..ff678de35e9943 100644 --- a/integration-tests/gradle/build.gradle +++ b/integration-tests/gradle/build.gradle @@ -27,17 +27,13 @@ repositories { mavenCentral() } -configurations.all { - exclude group: 'io.quarkus', module: 'quarkus-bootstrap-maven-resolver' -} - dependencies { + testImplementation "io.quarkus:quarkus-test-devtools:${version}" testImplementation "io.quarkus:quarkus-bootstrap-core:${version}" testImplementation "io.quarkus:quarkus-core-deployment:${version}" testImplementation "io.quarkus:quarkus-devmode-test-utils:${version}" testImplementation "io.quarkus:quarkus-devtools-common:${version}" testImplementation "io.quarkus:quarkus-platform-descriptor-json:${version}" - testImplementation "io.quarkus:quarkus-platform-descriptor-resolver-json:${version}" testImplementation "io.quarkus:io.quarkus.gradle.plugin:${version}" testImplementation 'org.mockito:mockito-core:3.8.0' testImplementation 'org.assertj:assertj-core:3.19.0' @@ -45,11 +41,21 @@ dependencies { testImplementation 'org.awaitility:awaitility:4.0.3' } +processTestResources { + filesMatching('.quarkus/config.yaml') { + expand(testResourcesDir: destinationDir) + } + filesMatching('test-registry-repo/**') { + expand(project.properties) + } +} + test { // propagate the custom local maven repo, in case it's configured if (System.properties.containsKey('maven.repo.local')) { systemProperty 'maven.repo.local', System.properties.get('maven.repo.local') } + systemProperty 'project.version', "${version}" useJUnitPlatform() // Kotlin compiler does not support Java 14 diff --git a/integration-tests/gradle/gradle.properties b/integration-tests/gradle/gradle.properties index 72a61ab94d2419..6b1bd1f00fe120 100644 --- a/integration-tests/gradle/gradle.properties +++ b/integration-tests/gradle/gradle.properties @@ -1 +1,3 @@ +quarkusPlatformArtifactId=quarkus-bom +quarkusPlatformGroupId=io.quarkus version = 999-SNAPSHOT diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToModuleInMultiModuleKtsProjectTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToModuleInMultiModuleKtsProjectTest.java index b822dae349dbc8..e42fae0ed98829 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToModuleInMultiModuleKtsProjectTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToModuleInMultiModuleKtsProjectTest.java @@ -11,7 +11,7 @@ import org.junit.jupiter.api.Test; -public class AddExtensionToModuleInMultiModuleKtsProjectTest extends QuarkusGradleWrapperTestBase { +public class AddExtensionToModuleInMultiModuleKtsProjectTest extends QuarkusGradleDevToolsTestBase { private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToModuleInMultiModuleProjectTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToModuleInMultiModuleProjectTest.java index 9c98a0d679d199..18b49e556cc957 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToModuleInMultiModuleProjectTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToModuleInMultiModuleProjectTest.java @@ -11,7 +11,7 @@ import org.junit.jupiter.api.Test; -public class AddExtensionToModuleInMultiModuleProjectTest extends QuarkusGradleWrapperTestBase { +public class AddExtensionToModuleInMultiModuleProjectTest extends QuarkusGradleDevToolsTestBase { private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToSingleModuleKtsProjectTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToSingleModuleKtsProjectTest.java index 4c66932a39f8e8..ab7ea55623e5dc 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToSingleModuleKtsProjectTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToSingleModuleKtsProjectTest.java @@ -10,7 +10,7 @@ import org.junit.jupiter.api.Test; -public class AddExtensionToSingleModuleKtsProjectTest extends QuarkusGradleWrapperTestBase { +public class AddExtensionToSingleModuleKtsProjectTest extends QuarkusGradleDevToolsTestBase { @Test public void testAddAndRemoveExtension() throws IOException, URISyntaxException, InterruptedException { diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToSingleModuleProjectTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToSingleModuleProjectTest.java index 40ee566171989c..9d6965d4547f69 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToSingleModuleProjectTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/AddExtensionToSingleModuleProjectTest.java @@ -10,7 +10,7 @@ import org.junit.jupiter.api.Test; -public class AddExtensionToSingleModuleProjectTest extends QuarkusGradleWrapperTestBase { +public class AddExtensionToSingleModuleProjectTest extends QuarkusGradleDevToolsTestBase { @Test public void testAddAndRemoveExtension() throws IOException, URISyntaxException, InterruptedException { diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/ListExtensionsTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/ListExtensionsTest.java index 5185de14bd9512..5d880c0300714e 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/ListExtensionsTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/ListExtensionsTest.java @@ -10,13 +10,13 @@ import org.junit.jupiter.api.Test; -public class ListExtensionsTest extends QuarkusGradleWrapperTestBase { +public class ListExtensionsTest extends QuarkusGradleDevToolsTestBase { @Test public void testListExtensionsWork() throws IOException, URISyntaxException, InterruptedException { final File projectDir = getProjectDir("list-extension-single-module"); - runGradleWrapper(projectDir, ":listExtension"); + runGradleWrapper(projectDir, ":listExtensions"); List<String> outputLogLines = listExtensions(projectDir, ":listExtension"); diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/QuarkusGradleDevToolsTestBase.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/QuarkusGradleDevToolsTestBase.java new file mode 100644 index 00000000000000..d8fa4d49832ca1 --- /dev/null +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/QuarkusGradleDevToolsTestBase.java @@ -0,0 +1,36 @@ +package io.quarkus.gradle; + +import java.nio.file.Paths; +import java.util.Map; +import java.util.Properties; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; + +import io.quarkus.devtools.test.DevToolsRegistryTestHelper; + +public class QuarkusGradleDevToolsTestBase extends QuarkusGradleWrapperTestBase { + + private static Properties devToolsProps = new Properties(2); + + @BeforeAll + static void enableDevToolsTestConfig() { + DevToolsRegistryTestHelper.enableDevToolsTestConfig(Paths.get("").normalize().toAbsolutePath().resolve("build"), + devToolsProps); + for (Map.Entry<?, ?> prop : devToolsProps.entrySet()) { + System.setProperty(prop.getKey().toString(), prop.getValue().toString()); + } + } + + @AfterAll + static void disableDevToolsTestConfig() { + DevToolsRegistryTestHelper.disableDevToolsTestConfig(); + } + + @Override + protected void setupTestCommand() { + for (Map.Entry<?, ?> prop : devToolsProps.entrySet()) { + setSystemProperty(prop.getKey().toString(), prop.getValue().toString()); + } + } +} diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/QuarkusGradleWrapperTestBase.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/QuarkusGradleWrapperTestBase.java index 18d7b7fb4f6e48..ddc00eb24dd81a 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/QuarkusGradleWrapperTestBase.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/QuarkusGradleWrapperTestBase.java @@ -7,9 +7,12 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.concurrent.TimeUnit; public class QuarkusGradleWrapperTestBase extends QuarkusGradleTestBase { @@ -19,7 +22,14 @@ public class QuarkusGradleWrapperTestBase extends QuarkusGradleTestBase { private static final String GRADLE_NO_DAEMON = "--no-daemon"; private static final String MAVEN_REPO_LOCAL = "maven.repo.local"; + private Map<String, String> systemProps; + + protected void setupTestCommand() { + + } + public BuildResult runGradleWrapper(File projectDir, String... args) throws IOException, InterruptedException { + setupTestCommand(); List<String> command = new LinkedList<>(); command.add(getGradleWrapperCommand()); command.add(GRADLE_NO_DAEMON); @@ -48,6 +58,13 @@ public BuildResult runGradleWrapper(File projectDir, String... args) throws IOEx } } + protected void setSystemProperty(String name, String value) { + if (systemProps == null) { + systemProps = new HashMap<>(); + } + systemProps.put(name, value); + } + private String getGradleWrapperCommand() { return Paths.get(getGradleWrapperName()).toAbsolutePath().toString(); } @@ -60,11 +77,27 @@ private String getGradleWrapperName() { } private List<String> getSytemProperties() { - List<String> systemProperties = new ArrayList<>(); - if (System.getProperties().containsKey(MAVEN_REPO_LOCAL)) { - systemProperties.add(String.format("-D%s=%s", MAVEN_REPO_LOCAL, System.getProperty(MAVEN_REPO_LOCAL))); + List<String> args = null; + if (systemProps != null) { + args = new ArrayList<>(systemProps.size() + 1); + for (Map.Entry<String, String> prop : systemProps.entrySet()) { + args.add(toPropertyArg(prop.getKey(), prop.getValue())); + } + } + final String mavenRepoLocal = System.getProperty(MAVEN_REPO_LOCAL); + if (mavenRepoLocal != null) { + final String arg = toPropertyArg(MAVEN_REPO_LOCAL, mavenRepoLocal); + if (args == null) { + args = Collections.singletonList(arg); + } else { + args.add(arg); + } } - return systemProperties; + return args == null ? Collections.emptyList() : args; + } + + private static String toPropertyArg(String name, String value) { + return new StringBuilder().append("-D=").append(name).append("=").append(value).toString(); } private void printCommandOutput(List<String> command, BuildResult commandResult) { diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/QuarkusPluginFunctionalTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/QuarkusPluginFunctionalTest.java index b6523fd3709fd5..d3829a0da725b8 100644 --- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/QuarkusPluginFunctionalTest.java +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/QuarkusPluginFunctionalTest.java @@ -18,11 +18,11 @@ import io.quarkus.devtools.commands.CreateProject; import io.quarkus.devtools.project.BuildTool; +import io.quarkus.devtools.project.QuarkusProjectHelper; import io.quarkus.devtools.project.codegen.SourceType; -import io.quarkus.platform.tools.config.QuarkusPlatformConfig; import io.quarkus.test.devmode.util.DevModeTestUtils; -public class QuarkusPluginFunctionalTest extends QuarkusGradleWrapperTestBase { +public class QuarkusPluginFunctionalTest extends QuarkusGradleDevToolsTestBase { private File projectRoot; @@ -164,12 +164,11 @@ public void canRunTest() throws Exception { private void createProject(SourceType sourceType) throws Exception { Map<String, Object> context = new HashMap<>(); context.put("path", "/greeting"); - assertThat(new CreateProject(projectRoot.toPath(), - QuarkusPlatformConfig.getGlobalDefault().getPlatformDescriptor()) + assertThat(new CreateProject(QuarkusProjectHelper.getProject(projectRoot.toPath(), + BuildTool.GRADLE)) .groupId("com.acme.foo") .artifactId("foo") .version("1.0.0-SNAPSHOT") - .buildTool(BuildTool.GRADLE) .className("org.acme.foo.GreetingResource") .sourceType(sourceType) .doCreateProject(context)) diff --git a/integration-tests/gradle/src/test/resources/.quarkus/config.yaml b/integration-tests/gradle/src/test/resources/.quarkus/config.yaml new file mode 100644 index 00000000000000..82f4783ee7130b --- /dev/null +++ b/integration-tests/gradle/src/test/resources/.quarkus/config.yaml @@ -0,0 +1,7 @@ +--- +debug: true +registries: +- test.registry.quarkus.io: + maven: + repository: + url: file://$testResourcesDir/test-registry-repo diff --git a/integration-tests/gradle/src/test/resources/test-registry-repo/io/quarkus/registry/test/quarkus-platforms/1.0-SNAPSHOT/quarkus-platforms-1.0-SNAPSHOT.json b/integration-tests/gradle/src/test/resources/test-registry-repo/io/quarkus/registry/test/quarkus-platforms/1.0-SNAPSHOT/quarkus-platforms-1.0-SNAPSHOT.json new file mode 100644 index 00000000000000..005be0766b3da3 --- /dev/null +++ b/integration-tests/gradle/src/test/resources/test-registry-repo/io/quarkus/registry/test/quarkus-platforms/1.0-SNAPSHOT/quarkus-platforms-1.0-SNAPSHOT.json @@ -0,0 +1,7 @@ +{ + "default-platform" : "$quarkusPlatformGroupId:$quarkusPlatformArtifactId::pom:$version", + "platforms" : [ { + "bom": "$quarkusPlatformGroupId:$quarkusPlatformArtifactId::pom:$version", + "quarkus-core-version": "$version" + } ] +} \ No newline at end of file diff --git a/integration-tests/gradle/src/test/resources/test-registry-repo/io/quarkus/registry/test/quarkus-registry-descriptor/1.0-SNAPSHOT/quarkus-registry-descriptor-1.0-SNAPSHOT.json b/integration-tests/gradle/src/test/resources/test-registry-repo/io/quarkus/registry/test/quarkus-registry-descriptor/1.0-SNAPSHOT/quarkus-registry-descriptor-1.0-SNAPSHOT.json new file mode 100644 index 00000000000000..c1a3b991ba2b12 --- /dev/null +++ b/integration-tests/gradle/src/test/resources/test-registry-repo/io/quarkus/registry/test/quarkus-registry-descriptor/1.0-SNAPSHOT/quarkus-registry-descriptor-1.0-SNAPSHOT.json @@ -0,0 +1,8 @@ +{ + "platforms" : { + "artifact" : "io.quarkus.registry.test:quarkus-platforms::json:1.0-SNAPSHOT" + }, + "non-platform-extensions" : { + "disabled" : true + } +} \ No newline at end of file diff --git a/integration-tests/kotlin/pom.xml b/integration-tests/kotlin/pom.xml index 617dee803b549e..b1cf0f5215bc12 100644 --- a/integration-tests/kotlin/pom.xml +++ b/integration-tests/kotlin/pom.xml @@ -29,6 +29,11 @@ <groupId>io.quarkus</groupId> <artifactId>quarkus-kotlin-deployment</artifactId> </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-bootstrap-maven-resolver</artifactId> + <scope>test</scope> + </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-platform-descriptor-json</artifactId> diff --git a/integration-tests/kotlin/src/test/java/io/quarkus/kotlin/maven/it/KotlinCreateMavenProjectIT.java b/integration-tests/kotlin/src/test/java/io/quarkus/kotlin/maven/it/KotlinCreateMavenProjectIT.java index ff46b7862acb3b..a287af51a1778c 100644 --- a/integration-tests/kotlin/src/test/java/io/quarkus/kotlin/maven/it/KotlinCreateMavenProjectIT.java +++ b/integration-tests/kotlin/src/test/java/io/quarkus/kotlin/maven/it/KotlinCreateMavenProjectIT.java @@ -77,6 +77,7 @@ private InvocationResult setup(Properties params) params.setProperty("platformArtifactId", "quarkus-bom"); params.setProperty("platformVersion", getQuarkusCoreVersion()); + enableDevToolsTestConfig(params); InvocationRequest request = new DefaultInvocationRequest(); request.setBatchMode(true); diff --git a/integration-tests/maven/pom.xml b/integration-tests/maven/pom.xml index bcfaede377a50c..840d608e604a7e 100644 --- a/integration-tests/maven/pom.xml +++ b/integration-tests/maven/pom.xml @@ -63,10 +63,6 @@ <directory>src/test/resources</directory> <filtering>true</filtering> </testResource> - <testResource> - <directory>src/it</directory> - <filtering>true</filtering> - </testResource> </testResources> <plugins> <plugin> diff --git a/integration-tests/maven/src/test/java/io/quarkus/maven/AddExtensionMojoTest.java b/integration-tests/maven/src/test/java/io/quarkus/maven/AddExtensionMojoTest.java index a99524f7b5da31..3f64e33c431c58 100644 --- a/integration-tests/maven/src/test/java/io/quarkus/maven/AddExtensionMojoTest.java +++ b/integration-tests/maven/src/test/java/io/quarkus/maven/AddExtensionMojoTest.java @@ -21,12 +21,15 @@ import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.resolution.ArtifactDescriptorResult; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContext; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; import io.quarkus.bootstrap.resolver.maven.workspace.ModelUtils; +import io.quarkus.devtools.test.DevToolsRegistryTestHelper; class AddExtensionMojoTest { @@ -35,6 +38,16 @@ class AddExtensionMojoTest { private static final String DEP_GAV = "org.apache.commons:commons-lang3:3.8.1"; private AddExtensionMojo mojo; + @BeforeAll + static void globalInit() { + DevToolsRegistryTestHelper.enableDevToolsTestConfig(); + } + + @AfterAll + static void globalCleanUp() { + DevToolsRegistryTestHelper.disableDevToolsTestConfig(); + } + @BeforeEach void init() throws Exception { mojo = getMojo(); diff --git a/integration-tests/maven/src/test/java/io/quarkus/maven/CreateExtensionLegacyMojoTest.java b/integration-tests/maven/src/test/java/io/quarkus/maven/CreateExtensionLegacyMojoTest.java deleted file mode 100644 index cb99c902be64e2..00000000000000 --- a/integration-tests/maven/src/test/java/io/quarkus/maven/CreateExtensionLegacyMojoTest.java +++ /dev/null @@ -1,272 +0,0 @@ -package io.quarkus.maven; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import java.util.UUID; -import java.util.stream.Collectors; - -import org.apache.maven.model.Build; -import org.apache.maven.model.Dependency; -import org.apache.maven.model.Model; -import org.apache.maven.model.PluginManagement; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.project.MavenProject; -import org.junit.jupiter.api.Test; - -import io.quarkus.maven.utilities.MojoUtils; - -public class CreateExtensionLegacyMojoTest { - - private static CreateExtensionLegacyMojo initMojo(final Path projectDir) throws IOException { - final CreateExtensionLegacyMojo mojo = new CreateExtensionLegacyMojo(); - mojo.project = new MavenProject(); - mojo.basedir = projectDir.toFile(); - mojo.generateDevModeTest = true; - mojo.generateUnitTest = true; - - final File pom = new File(projectDir.toFile(), "pom.xml"); - if (pom.exists()) { - mojo.project.setFile(pom); - final Model rawModel = MojoUtils.readPom(pom); - // the project would have an interpolated model at runtime, which we can't fully init here - // here are just some key parts - if (rawModel.getDependencyManagement() != null) { - List<Dependency> deps = rawModel.getDependencyManagement().getDependencies(); - if (deps != null && !deps.isEmpty()) { - Dependency deploymentBom = null; - for (Dependency dep : deps) { - if (dep.getArtifactId().equals("quarkus-bom") && dep.getGroupId().equals("io.quarkus")) { - deploymentBom = dep; - } - } - if (deploymentBom != null) { - String version = deploymentBom.getVersion(); - if (CreateExtensionLegacyMojo.QUARKUS_VERSION_POM_EXPR.equals(version)) { - version = rawModel.getProperties().getProperty(version.substring(2, version.length() - 1)); - if (version == null) { - throw new IllegalStateException( - "Failed to resolve " + deploymentBom.getVersion() + " from " + pom); - } - } - Dependency dep = new Dependency(); - dep.setGroupId("io.quarkus"); - dep.setArtifactId("quarkus-core-deployment"); - dep.setType("jar"); - dep.setVersion(version); - deps.add(dep); - } - } - } - mojo.project.setModel(rawModel); - } - - Build build = mojo.project.getBuild(); - if (build.getPluginManagement() == null) { - build.setPluginManagement(new PluginManagement()); - } - - mojo.encoding = CreateExtensionLegacyMojo.DEFAULT_ENCODING; - mojo.templatesUriBase = CreateExtensionLegacyMojo.DEFAULT_TEMPLATES_URI_BASE; - mojo.quarkusVersion = CreateExtensionLegacyMojo.DEFAULT_QUARKUS_VERSION; - mojo.bomEntryVersion = CreateExtensionLegacyMojo.DEFAULT_BOM_ENTRY_VERSION; - mojo.assumeManaged = true; - mojo.nameSegmentDelimiter = CreateExtensionLegacyMojo.DEFAULT_NAME_SEGMENT_DELIMITER; - mojo.platformGroupId = CreateExtensionLegacyMojo.PLATFORM_DEFAULT_GROUP_ID; - mojo.platformArtifactId = CreateExtensionLegacyMojo.PLATFORM_DEFAULT_ARTIFACT_ID; - mojo.compilerPluginVersion = CreateExtensionLegacyMojo.COMPILER_PLUGIN_DEFAULT_VERSION; - return mojo; - } - - private static Path createProjectFromTemplate(String testProjectName) throws IOException { - final Path srcDir = Paths.get("src/test/resources/projects/" + testProjectName); - /* - * We want to run on the same project multiple times with different args so let's create a copy with a random - * suffix - */ - final Path copyDir = newProjectDir(testProjectName); - Files.walk(srcDir).forEach(source -> { - final Path dest = copyDir.resolve(srcDir.relativize(source)); - try { - Files.copy(source, dest); - } catch (IOException e) { - if (!Files.isDirectory(dest)) { - throw new RuntimeException(e); - } - } - }); - return copyDir; - } - - private static Path newProjectDir(String testProjectName) throws IOException { - int count = 0; - while (count < 100) { - Path path = Paths.get("target/test-classes/projects/" + testProjectName + "-" + UUID.randomUUID()); - if (!Files.exists(path)) { - Files.createDirectories(path); - return path; - } - count++; - } - - // if we have tried too many times we just give up instead of looping forever which could cause the test to never end - throw new RuntimeException("Unable to create a directory for copying the test application into"); - } - - @Test - void createExtensionUnderExistingPomMinimal() throws MojoExecutionException, MojoFailureException, - IllegalArgumentException, SecurityException, IOException { - final CreateExtensionLegacyMojo mojo = initMojo(createProjectFromTemplate("create-extension-pom")); - mojo.artifactId = "my-project-(minimal-extension)"; - mojo.assumeManaged = false; - mojo.execute(); - - assertTreesMatch(Paths.get("src/test/resources/expected/create-extension-pom-minimal"), - mojo.basedir.toPath()); - } - - @Test - void createExtensionUnderExistingPomWithAdditionalRuntimeDependencies() throws MojoExecutionException, MojoFailureException, - IllegalArgumentException, SecurityException, IOException { - final CreateExtensionLegacyMojo mojo = initMojo(createProjectFromTemplate("create-extension-pom")); - mojo.artifactId = "my-project-(add-to-bom)"; - mojo.assumeManaged = false; - mojo.bomPath = Paths.get("bom/pom.xml"); - mojo.additionalRuntimeDependencies = Arrays.asList("org.example:example-1:1.2.3", - "org.acme:acme-@{quarkus.artifactIdBase}:@{$}{acme.version}"); - mojo.execute(); - - assertTreesMatch(Paths.get("src/test/resources/expected/create-extension-pom-add-to-bom"), - mojo.basedir.toPath()); - } - - @Test - void createExtensionUnderExistingPomWithItest() throws MojoExecutionException, MojoFailureException, - IllegalArgumentException, SecurityException, IOException { - final CreateExtensionLegacyMojo mojo = initMojo(createProjectFromTemplate("create-extension-pom")); - mojo.artifactId = "my-project-(itest)"; - mojo.assumeManaged = false; - mojo.itestParentPath = Paths.get("integration-tests/pom.xml"); - mojo.execute(); - - assertTreesMatch(Paths.get("src/test/resources/expected/create-extension-pom-itest"), - mojo.basedir.toPath()); - } - - @Test - void createExtensionUnderExistingPomCustomGrandParent() throws MojoExecutionException, MojoFailureException, - IllegalArgumentException, SecurityException, IOException { - final CreateExtensionLegacyMojo mojo = initMojo(createProjectFromTemplate("create-extension-pom")); - mojo.artifactId = "myproject-(with-grand-parent)"; - mojo.parentArtifactId = "grand-parent"; - mojo.parentRelativePath = "../pom.xml"; - mojo.templatesUriBase = "file:templates"; - - mojo.bomPath = Paths.get("bom/pom.xml"); - mojo.execute(); - assertTreesMatch( - Paths.get("src/test/resources/expected/create-extension-pom-with-grand-parent"), - mojo.basedir.toPath()); - } - - @Test - void createNewExtensionProject() throws Exception { - final CreateExtensionLegacyMojo mojo = initMojo(newProjectDir("new-ext-project")); - mojo.groupId = "org.acme"; - mojo.artifactId = "my-ext"; - mojo.version = "1.0-SNAPSHOT"; - mojo.assumeManaged = null; - mojo.execute(); - assertTreesMatch( - Paths.get("target/test-classes/expected/new-extension-project"), - mojo.basedir.toPath()); - } - - @Test - void createNewExtensionOnCurrentDirectory() throws Exception { - final CreateExtensionLegacyMojo mojo = initMojo(newProjectDir("new-extension-current-directory-project")); - mojo.groupId = "org.acme"; - mojo.artifactId = "my-ext"; - mojo.version = "1.0-SNAPSHOT"; - mojo.useCurrentDirectory = true; - mojo.assumeManaged = null; - mojo.execute(); - assertTreesMatch( - Paths.get("target/test-classes/expected/new-extension-current-directory-project"), - mojo.basedir.toPath()); - } - - @Test - void createNewExtensionProjectWithJBossParent() throws Exception { - final CreateExtensionLegacyMojo mojo = initMojo(newProjectDir("new-ext-project-with-jboss-parent")); - mojo.parentGroupId = "org.jboss"; - mojo.parentArtifactId = "jboss-parent"; - mojo.parentVersion = "37"; - mojo.groupId = "org.acme"; - mojo.artifactId = "my-ext"; - mojo.version = "1.0-SNAPSHOT"; - mojo.assumeManaged = null; - mojo.execute(); - assertTreesMatch( - Paths.get("target/test-classes/expected/new-extension-project-with-jboss-parent"), - mojo.basedir.toPath()); - } - - static void assertTreesMatch(Path expected, Path actual) throws IOException { - final Set<Path> expectedFiles = new LinkedHashSet<>(); - Files.walk(expected).filter(Files::isRegularFile).forEach(p -> { - final Path relative = expected.relativize(p); - expectedFiles.add(relative); - final Path actualPath = actual.resolve(relative); - try { - String expectedContent = new String(Files.readAllBytes(p), StandardCharsets.UTF_8); - String actualContent = new String(Files.readAllBytes(actualPath), StandardCharsets.UTF_8); - if (System.getProperty("os.name").toLowerCase(Locale.ROOT).startsWith("windows")) { - expectedContent = expectedContent.replace(System.lineSeparator(), "\n"); - actualContent = actualContent.replace(System.lineSeparator(), "\n"); - } - assertEquals(expectedContent, actualContent); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - - final Set<Path> unexpectedFiles = new LinkedHashSet<>(); - Files.walk(actual).filter(Files::isRegularFile).forEach(p -> { - final Path relative = actual.relativize(p); - if (!expectedFiles.contains(relative)) { - unexpectedFiles.add(relative); - } - }); - if (!unexpectedFiles.isEmpty()) { - fail(String.format("Files found under [%s] but not defined as expected under [%s]:%s", actual, - expected, unexpectedFiles.stream().map(Path::toString).collect(Collectors.joining("\n ")))); - } - } - - @Test - void getPackage() { - assertEquals("org.apache.camel.quarkus.aws.sns.deployment", CreateExtensionLegacyMojo - .getJavaPackage("org.apache.camel.quarkus", null, "camel-quarkus-aws-sns-deployment")); - assertEquals("org.apache.camel.quarkus.component.aws.sns.deployment", CreateExtensionLegacyMojo - .getJavaPackage("org.apache.camel.quarkus", "component", "camel-quarkus-aws-sns-deployment")); - } - - @Test - void toCapCamelCase() { - assertEquals("FooBarBaz", CreateExtensionLegacyMojo.toCapCamelCase("foo-bar-baz")); - } - -} diff --git a/integration-tests/maven/src/test/java/io/quarkus/maven/it/AddExtensionIT.java b/integration-tests/maven/src/test/java/io/quarkus/maven/it/AddExtensionIT.java index cc41f11ae2a0a3..e2202e8a55430b 100644 --- a/integration-tests/maven/src/test/java/io/quarkus/maven/it/AddExtensionIT.java +++ b/integration-tests/maven/src/test/java/io/quarkus/maven/it/AddExtensionIT.java @@ -139,7 +139,9 @@ private void addExtension(boolean plural, String ext) } else { properties.setProperty("extension", ext); } + enableDevToolsTestConfig(properties); request.setProperties(properties); + getEnv().forEach(request::addShellEnvironment); File log = new File(testDir, "build-add-extension-" + testDir.getName() + ".log"); PrintStreamLogger logger = new PrintStreamLogger(new PrintStream(new FileOutputStream(log), false, "UTF-8"), diff --git a/integration-tests/maven/src/test/java/io/quarkus/maven/it/CreateJBangProjectMojoIT.java b/integration-tests/maven/src/test/java/io/quarkus/maven/it/CreateJBangProjectMojoIT.java index 90421d68ada506..760dc86d0b2dd7 100644 --- a/integration-tests/maven/src/test/java/io/quarkus/maven/it/CreateJBangProjectMojoIT.java +++ b/integration-tests/maven/src/test/java/io/quarkus/maven/it/CreateJBangProjectMojoIT.java @@ -51,6 +51,7 @@ private InvocationResult setup(Properties params) getMavenPluginGroupId() + ":" + getMavenPluginArtifactId() + ":" + getMavenPluginVersion() + ":create-jbang")); request.setDebug(false); request.setShowErrors(true); + enableDevToolsTestConfig(params); request.setProperties(params); getEnv().forEach(request::addShellEnvironment); File log = new File(testDir, "build-create-" + testDir.getName() + ".log"); diff --git a/integration-tests/maven/src/test/java/io/quarkus/maven/it/CreateProjectCodestartMojoIT.java b/integration-tests/maven/src/test/java/io/quarkus/maven/it/CreateProjectCodestartMojoIT.java index 0dd71949149a04..3748ed2a673da8 100644 --- a/integration-tests/maven/src/test/java/io/quarkus/maven/it/CreateProjectCodestartMojoIT.java +++ b/integration-tests/maven/src/test/java/io/quarkus/maven/it/CreateProjectCodestartMojoIT.java @@ -160,7 +160,9 @@ private InvocationResult executeCreate(Properties params) getMavenPluginGroupId() + ":" + getMavenPluginArtifactId() + ":" + getMavenPluginVersion() + ":create")); request.setDebug(false); request.setShowErrors(true); + enableDevToolsTestConfig(params); request.setProperties(params); + getEnv().forEach(request::addShellEnvironment); PrintStreamLogger logger = getPrintStreamLogger("create-codestart.log"); invoker.setLogger(logger); diff --git a/integration-tests/maven/src/test/java/io/quarkus/maven/it/CreateProjectMojoIT.java b/integration-tests/maven/src/test/java/io/quarkus/maven/it/CreateProjectMojoIT.java index d2ebba6f4e3d44..dd73536b451f03 100644 --- a/integration-tests/maven/src/test/java/io/quarkus/maven/it/CreateProjectMojoIT.java +++ b/integration-tests/maven/src/test/java/io/quarkus/maven/it/CreateProjectMojoIT.java @@ -61,6 +61,7 @@ public void testProjectGenerationFromScratch() throws MavenInvocationException, properties.put("projectGroupId", "org.acme"); properties.put("projectArtifactId", "acme"); properties.put("projectVersion", "1.0.0-SNAPSHOT"); + InvocationResult result = setup(properties); assertThat(result.getExitCode()).isZero(); @@ -438,6 +439,7 @@ private InvocationResult setup(Properties params) getMavenPluginGroupId() + ":" + getMavenPluginArtifactId() + ":" + getMavenPluginVersion() + ":create")); request.setDebug(false); request.setShowErrors(true); + enableDevToolsTestConfig(params); request.setProperties(params); getEnv().forEach(request::addShellEnvironment); File log = new File(testDir, "build-create-" + testDir.getName() + ".log"); @@ -446,5 +448,4 @@ private InvocationResult setup(Properties params) invoker.setLogger(logger); return invoker.execute(request); } - } diff --git a/integration-tests/maven/src/test/java/io/quarkus/maven/it/ListExtensionsIT.java b/integration-tests/maven/src/test/java/io/quarkus/maven/it/ListExtensionsIT.java index 3edcc11e4d4e12..0f684b26134dd6 100644 --- a/integration-tests/maven/src/test/java/io/quarkus/maven/it/ListExtensionsIT.java +++ b/integration-tests/maven/src/test/java/io/quarkus/maven/it/ListExtensionsIT.java @@ -65,6 +65,7 @@ private List<String> listExtensions() getMavenPluginGroupId() + ":" + getMavenPluginArtifactId() + ":" + getMavenPluginVersion() + ":list-extensions")); getEnv().forEach(request::addShellEnvironment); + enableDevToolsTestConfig(request); File outputLog = new File(testDir, "output.log"); InvocationOutputHandler outputHandler = new PrintStreamHandler( diff --git a/integration-tests/scala/pom.xml b/integration-tests/scala/pom.xml index ad266e97853a3f..d8f7e63b69104a 100644 --- a/integration-tests/scala/pom.xml +++ b/integration-tests/scala/pom.xml @@ -25,12 +25,12 @@ </dependency> <dependency> <groupId>io.quarkus</groupId> - <artifactId>quarkus-test-maven</artifactId> + <artifactId>quarkus-bootstrap-maven-resolver</artifactId> <scope>test</scope> </dependency> <dependency> - <groupId>org.apache.maven</groupId> - <artifactId>maven-model</artifactId> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-test-maven</artifactId> <scope>test</scope> </dependency> <dependency> diff --git a/integration-tests/scala/src/test/java/io/quarkus/scala/maven/it/ScalaCreateMavenProjectIT.java b/integration-tests/scala/src/test/java/io/quarkus/scala/maven/it/ScalaCreateMavenProjectIT.java index 4a25f04bba3e6e..895636aa9c82c4 100644 --- a/integration-tests/scala/src/test/java/io/quarkus/scala/maven/it/ScalaCreateMavenProjectIT.java +++ b/integration-tests/scala/src/test/java/io/quarkus/scala/maven/it/ScalaCreateMavenProjectIT.java @@ -84,6 +84,7 @@ private InvocationResult setup(Properties params) } params.setProperty("platformArtifactId", getBomArtifactId()); params.setProperty("platformVersion", getQuarkusCoreVersion()); + enableDevToolsTestConfig(params); InvocationRequest request = new DefaultInvocationRequest(); request.setBatchMode(true); diff --git a/test-framework/devtools/pom.xml b/test-framework/devtools/pom.xml new file mode 100644 index 00000000000000..a8edb0e9a338e0 --- /dev/null +++ b/test-framework/devtools/pom.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-test-framework</artifactId> + <version>999-SNAPSHOT</version> + </parent> + + <artifactId>quarkus-test-devtools</artifactId> + <name>Quarkus - Test Framework - Dev Tools</name> + + <dependencies> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-devtools-registry-client</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + +</project> diff --git a/test-framework/devtools/src/main/java/io/quarkus/devtools/test/DevToolsRegistryTestHelper.java b/test-framework/devtools/src/main/java/io/quarkus/devtools/test/DevToolsRegistryTestHelper.java new file mode 100644 index 00000000000000..e61b6203ac4e73 --- /dev/null +++ b/test-framework/devtools/src/main/java/io/quarkus/devtools/test/DevToolsRegistryTestHelper.java @@ -0,0 +1,139 @@ +package io.quarkus.devtools.test; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.Properties; + +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.Constants; +import io.quarkus.registry.catalog.json.JsonCatalogMapperHelper; +import io.quarkus.registry.catalog.json.JsonPlatform; +import io.quarkus.registry.catalog.json.JsonPlatformCatalog; +import io.quarkus.registry.config.RegistriesConfigLocator; +import io.quarkus.registry.config.json.JsonRegistriesConfig; +import io.quarkus.registry.config.json.JsonRegistryConfig; +import io.quarkus.registry.config.json.JsonRegistryMavenConfig; +import io.quarkus.registry.config.json.JsonRegistryMavenRepoConfig; +import io.quarkus.registry.config.json.JsonRegistryNonPlatformExtensionsConfig; +import io.quarkus.registry.config.json.JsonRegistryPlatformsConfig; +import io.quarkus.registry.config.json.RegistriesConfigMapperHelper; + +public class DevToolsRegistryTestHelper { + + public static void enableDevToolsTestConfig() { + enableDevToolsTestConfig(System.getProperties()); + } + + public static void enableDevToolsTestConfig(Properties properties) { + enableDevToolsTestConfig(Paths.get("").normalize().toAbsolutePath().resolve("target"), + properties); + } + + public static void enableDevToolsTestConfig(Path outputDir, Properties properties) { + final Path toolsConfigPath = outputDir.resolve(RegistriesConfigLocator.CONFIG_RELATIVE_PATH); + final Path registryRepoPath = outputDir.resolve("test-registry-repo"); + final Path groupIdDir = registryRepoPath.resolve("io/quarkus/registry/test"); + + generateToolsConfig(toolsConfigPath, registryRepoPath); + generateRegistryDescriptor(groupIdDir); + generatePlatformCatalog(groupIdDir); + + properties.setProperty("io.quarkus.maven.secondary-local-repo", registryRepoPath.toString()); + properties.setProperty(RegistriesConfigLocator.CONFIG_FILE_PATH_PROPERTY, toolsConfigPath.toString()); + } + + private static void generatePlatformCatalog(final Path groupIdDir) { + final String projectVersion = System.getProperty("project.version"); + if (projectVersion == null) { + throw new IllegalStateException("System property project.version isn't set"); + } + final Path platformsPath = groupIdDir.resolve(Constants.DEFAULT_REGISTRY_PLATFORMS_CATALOG_ARTIFACT_ID) + .resolve(Constants.DEFAULT_REGISTRY_ARTIFACT_VERSION) + .resolve(Constants.DEFAULT_REGISTRY_PLATFORMS_CATALOG_ARTIFACT_ID + "-" + + Constants.DEFAULT_REGISTRY_ARTIFACT_VERSION + ".json"); + final Path versionedPlatformsPath = groupIdDir.resolve(Constants.DEFAULT_REGISTRY_PLATFORMS_CATALOG_ARTIFACT_ID) + .resolve(Constants.DEFAULT_REGISTRY_ARTIFACT_VERSION) + .resolve(Constants.DEFAULT_REGISTRY_PLATFORMS_CATALOG_ARTIFACT_ID + "-" + + Constants.DEFAULT_REGISTRY_ARTIFACT_VERSION + "-" + projectVersion + ".json"); + if (Files.exists(platformsPath) && Files.exists(versionedPlatformsPath)) { + return; + } + final ArtifactCoords bom = new ArtifactCoords("io.quarkus", "quarkus-bom", null, "pom", projectVersion); + final JsonPlatformCatalog platforms = new JsonPlatformCatalog(); + platforms.setDefaultPlatform(bom); + final JsonPlatform platform = new JsonPlatform(); + platforms.addPlatform(platform); + platform.setBom(bom); + platform.setQuarkusCoreVersion(projectVersion); + try { + JsonCatalogMapperHelper.serialize(platforms, platformsPath); + Files.copy(platformsPath, versionedPlatformsPath, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + throw new IllegalStateException("Failed to persist registry platforms config", e); + } + } + + private static void generateRegistryDescriptor(Path repoGroupIdDir) { + final Path descriptorPath = repoGroupIdDir.resolve(Constants.DEFAULT_REGISTRY_DESCRIPTOR_ARTIFACT_ID) + .resolve(Constants.DEFAULT_REGISTRY_ARTIFACT_VERSION).resolve(Constants.DEFAULT_REGISTRY_DESCRIPTOR_ARTIFACT_ID + + "-" + Constants.DEFAULT_REGISTRY_ARTIFACT_VERSION + ".json"); + if (Files.exists(descriptorPath)) { + return; + } + final JsonRegistryConfig descriptor = new JsonRegistryConfig(); + final JsonRegistryPlatformsConfig platformsConfig = new JsonRegistryPlatformsConfig(); + descriptor.setPlatforms(platformsConfig); + platformsConfig.setArtifact( + new ArtifactCoords("io.quarkus.registry.test", Constants.DEFAULT_REGISTRY_PLATFORMS_CATALOG_ARTIFACT_ID, null, + "json", Constants.DEFAULT_REGISTRY_ARTIFACT_VERSION)); + final JsonRegistryNonPlatformExtensionsConfig nonPlatformsConfig = new JsonRegistryNonPlatformExtensionsConfig(); + descriptor.setNonPlatformExtensions(nonPlatformsConfig); + nonPlatformsConfig.setDisabled(true); + try { + RegistriesConfigMapperHelper.serialize(descriptor, descriptorPath); + } catch (IOException e) { + throw new IllegalStateException("Failed to persist the registry descriptor", e); + } + } + + private static void generateToolsConfig(Path toolsConfigPath, Path registryRepoPath) { + if (Files.exists(toolsConfigPath)) { + return; + } + final JsonRegistryConfig registryConfig = new JsonRegistryConfig(); + registryConfig.setId("test.registry.quarkus.io"); + final JsonRegistryMavenConfig mavenConfig = new JsonRegistryMavenConfig(); + registryConfig.setMaven(mavenConfig); + final JsonRegistryMavenRepoConfig repoConfig = new JsonRegistryMavenRepoConfig(); + mavenConfig.setRepository(repoConfig); + try { + repoConfig.setUrl(registryRepoPath.toUri().toURL().toString()); + } catch (MalformedURLException e) { + throw new IllegalStateException("Failed to translate a path to url", e); + } + + final JsonRegistriesConfig toolsConfig = new JsonRegistriesConfig(); + toolsConfig.addRegistry(registryConfig); + toolsConfig.setDebug(true); + + try { + RegistriesConfigMapperHelper.serialize(toolsConfig, + toolsConfigPath); + } catch (IOException e) { + throw new IllegalStateException("Failed to persist the tools config", e); + } + } + + public static void disableDevToolsTestConfig() { + disableDevToolsTestConfig(System.getProperties()); + } + + public static void disableDevToolsTestConfig(Properties properties) { + properties.remove("io.quarkus.maven.secondary-local-repo"); + properties.remove(RegistriesConfigLocator.CONFIG_FILE_PATH_PROPERTY); + } +} diff --git a/test-framework/maven/pom.xml b/test-framework/maven/pom.xml index ade8ac27fa23fb..43df88db9cbd96 100644 --- a/test-framework/maven/pom.xml +++ b/test-framework/maven/pom.xml @@ -16,15 +16,15 @@ <dependencies> <dependency> <groupId>io.quarkus</groupId> - <artifactId>quarkus-devmode-test-utils</artifactId> + <artifactId>quarkus-test-devtools</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> - <artifactId>quarkus-devtools-common</artifactId> + <artifactId>quarkus-devmode-test-utils</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> - <artifactId>quarkus-platform-descriptor-resolver-json</artifactId> + <artifactId>quarkus-devtools-common</artifactId> </dependency> <dependency> <groupId>org.apache.maven.shared</groupId> diff --git a/test-framework/maven/src/main/java/io/quarkus/maven/it/MojoTestBase.java b/test-framework/maven/src/main/java/io/quarkus/maven/it/MojoTestBase.java index f36d1604a4dfbe..de71d2d74cf616 100644 --- a/test-framework/maven/src/main/java/io/quarkus/maven/it/MojoTestBase.java +++ b/test-framework/maven/src/main/java/io/quarkus/maven/it/MojoTestBase.java @@ -12,6 +12,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Properties; import java.util.function.Predicate; import java.util.logging.Level; import java.util.logging.Logger; @@ -21,9 +22,11 @@ import org.apache.maven.model.Model; import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import org.apache.maven.shared.invoker.DefaultInvoker; +import org.apache.maven.shared.invoker.InvocationRequest; import org.apache.maven.shared.invoker.Invoker; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; +import io.quarkus.devtools.test.DevToolsRegistryTestHelper; import io.quarkus.test.devmode.util.DevModeTestUtils; public class MojoTestBase { @@ -49,6 +52,7 @@ public static File initEmptyProject(String name) { } } boolean mkdirs = tc.mkdirs(); + Logger.getLogger(MojoTestBase.class.getName()) .log(Level.FINE, "test-classes created? %s", mkdirs); return tc; @@ -140,4 +144,20 @@ public static List<File> getFilesEndingWith(File dir, String suffix) { return files != null ? Arrays.asList(files) : Collections.emptyList(); } + public static void enableDevToolsTestConfig(InvocationRequest request) { + Properties properties = request.getProperties(); + if (properties == null) { + properties = new Properties(); + request.setProperties(properties); + } + enableDevToolsTestConfig(properties); + } + + public static void enableDevToolsTestConfig(Properties properties) { + DevToolsRegistryTestHelper.enableDevToolsTestConfig(properties); + } + + public static void disableDevToolsTestConfig(Properties properties) { + DevToolsRegistryTestHelper.disableDevToolsTestConfig(properties); + } } diff --git a/test-framework/maven/src/main/java/io/quarkus/maven/it/QuarkusPlatformAwareMojoTestBase.java b/test-framework/maven/src/main/java/io/quarkus/maven/it/QuarkusPlatformAwareMojoTestBase.java index 9b401ae8dc0365..b0120149d94e7a 100644 --- a/test-framework/maven/src/main/java/io/quarkus/maven/it/QuarkusPlatformAwareMojoTestBase.java +++ b/test-framework/maven/src/main/java/io/quarkus/maven/it/QuarkusPlatformAwareMojoTestBase.java @@ -2,25 +2,32 @@ import java.util.Properties; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.descriptor.resolver.json.QuarkusJsonPlatformDescriptorResolver; +import io.quarkus.devtools.project.QuarkusProjectHelper; import io.quarkus.platform.tools.ToolsUtils; +import io.quarkus.registry.RegistryResolutionException; +import io.quarkus.registry.catalog.ExtensionCatalog; public class QuarkusPlatformAwareMojoTestBase extends MojoTestBase { - private QuarkusPlatformDescriptor platformDescr; + private ExtensionCatalog catalog; private Properties quarkusProps; - protected QuarkusPlatformDescriptor getPlatformDescriptor() { - return platformDescr == null ? platformDescr = QuarkusJsonPlatformDescriptorResolver.newInstance().resolveBundled() - : platformDescr; + private ExtensionCatalog getPlatformDescriptor() { + if (catalog == null) { + enableDevToolsTestConfig(System.getProperties()); + try { + catalog = QuarkusProjectHelper.getCatalogResolver().resolveExtensionCatalog(); + } catch (RegistryResolutionException e) { + throw new RuntimeException("Failed to resolve the extensions catalog", e); + } finally { + disableDevToolsTestConfig(System.getProperties()); + } + } + return catalog; } private Properties getQuarkusProperties() { - if (quarkusProps == null) { - quarkusProps = ToolsUtils.readQuarkusProperties(getPlatformDescriptor()); - } - return quarkusProps; + return quarkusProps == null ? quarkusProps = ToolsUtils.readQuarkusProperties(getPlatformDescriptor()) : quarkusProps; } protected String getMavenPluginGroupId() { @@ -40,14 +47,14 @@ protected String getQuarkusCoreVersion() { } protected String getBomGroupId() { - return getPlatformDescriptor().getBomGroupId(); + return getPlatformDescriptor().getBom().getGroupId(); } protected String getBomArtifactId() { - return getPlatformDescriptor().getBomArtifactId(); + return getPlatformDescriptor().getBom().getArtifactId(); } protected String getBomVersion() { - return getPlatformDescriptor().getBomVersion(); + return getPlatformDescriptor().getBom().getVersion(); } } diff --git a/test-framework/maven/src/main/java/io/quarkus/maven/it/assertions/SetupVerifier.java b/test-framework/maven/src/main/java/io/quarkus/maven/it/assertions/SetupVerifier.java index 6f51cc0a7a731f..70f38ff685a97d 100644 --- a/test-framework/maven/src/main/java/io/quarkus/maven/it/assertions/SetupVerifier.java +++ b/test-framework/maven/src/main/java/io/quarkus/maven/it/assertions/SetupVerifier.java @@ -17,10 +17,11 @@ import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.xml.Xpp3Dom; +import io.quarkus.devtools.project.QuarkusProjectHelper; +import io.quarkus.devtools.test.DevToolsRegistryTestHelper; import io.quarkus.maven.utilities.MojoUtils; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.descriptor.resolver.json.QuarkusJsonPlatformDescriptorResolver; import io.quarkus.platform.tools.ToolsConstants; +import io.quarkus.registry.catalog.ExtensionCatalog; public class SetupVerifier { @@ -111,11 +112,16 @@ public static void verifySetupWithVersion(File pomFile) throws Exception { Properties projectProps = project.getProperties(); assertNotNull(projectProps); assertFalse(projectProps.isEmpty()); - final String quarkusVersion = getPlatformDescriptor().getQuarkusVersion(); + final String quarkusVersion = getPlatformDescriptor().getQuarkusCoreVersion(); assertEquals(quarkusVersion, projectProps.getProperty(MojoUtils.TEMPLATE_PROPERTY_QUARKUS_PLUGIN_VERSION_NAME)); } - private static QuarkusPlatformDescriptor getPlatformDescriptor() { - return QuarkusJsonPlatformDescriptorResolver.newInstance().resolveBundled(); + private static ExtensionCatalog getPlatformDescriptor() throws Exception { + DevToolsRegistryTestHelper.enableDevToolsTestConfig(); + try { + return QuarkusProjectHelper.getCatalogResolver().resolveExtensionCatalog(); + } finally { + DevToolsRegistryTestHelper.disableDevToolsTestConfig(); + } } } diff --git a/test-framework/pom.xml b/test-framework/pom.xml index 0321e590d9e206..65c5659605d553 100644 --- a/test-framework/pom.xml +++ b/test-framework/pom.xml @@ -31,6 +31,7 @@ <module>amazon-lambda</module> <module>arquillian</module> <module>devmode-test-utils</module> + <module>devtools</module> <module>maven</module> <module>vault</module> <module>ldap</module> diff --git a/update-extension-dependencies.sh b/update-extension-dependencies.sh index 97e1c81701b55d..74bc73c50e7dfc 100755 --- a/update-extension-dependencies.sh +++ b/update-extension-dependencies.sh @@ -32,7 +32,7 @@ echo '' # get all "artifact-id" values from the generated json file # pipefail is switched off briefly so that a better error can be logged when nothing is found set +o pipefail -ARTIFACT_IDS=`grep -Po '(?<="artifact-id": ")(?!quarkus-bom)[^"]+' devtools/bom-descriptor-json/target/*.json | sort` +ARTIFACT_IDS=`grep '"artifact"' devtools/bom-descriptor-json/target/*.json | grep -Po '(?<=io.quarkus:)(?!quarkus-bom)[^:]+' | sort` set -o pipefail if [ -z "${ARTIFACT_IDS}" ] then