Skip to content

Commit

Permalink
maven plugin goal generating extensions.json for a BOM
Browse files Browse the repository at this point in the history
  • Loading branch information
aloubyansky committed Sep 20, 2019
1 parent bd3e6d7 commit c80e58e
Show file tree
Hide file tree
Showing 5 changed files with 280 additions and 0 deletions.
1 change: 1 addition & 0 deletions build-parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@
<version>${project.version}</version>
<executions>
<execution>
<id>generate-extension-descriptor</id>
<goals>
<goal>extension-descriptor</goal>
</goals>
Expand Down
5 changes: 5 additions & 0 deletions devtools/maven/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@
<artifactId>freemarker</artifactId>
</dependency>

<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
</dependency>

<!-- extensions reader -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
package io.quarkus.maven;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Properties;

import javax.json.Json;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObjectBuilder;
import javax.json.JsonWriter;
import javax.json.JsonWriterFactory;
import javax.json.stream.JsonGenerator;

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.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.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 io.quarkus.bootstrap.BootstrapConstants;
import io.quarkus.bootstrap.BootstrapDependencyProcessingException;
import io.quarkus.bootstrap.resolver.maven.DeploymentInjectionException;
import io.quarkus.bootstrap.util.ZipUtils;

/**
* 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.
*/
@Mojo(name = "generate-extensions-json")
public class GenerateExtensionsJsonMojo extends AbstractMojo {

private static final String PROP_ARTIFACT_ID = "artifactId";
private static final String PROP_GROUP_ID = "groupId";
private static final String PROP_GUIDE = "guide";
private static final String PROP_LABELS = "labels";
private static final String PROP_NAME = "name";
private static final String PROP_SHORT_NAME = "shortName";

@Parameter(property = "bomGroupId", defaultValue = "io.quarkus")
private String bomGroupId;

@Parameter(property = "bomArtifactId", defaultValue = "quarkus-bom")
private String bomArtifactId;

@Parameter(property = "bomVersion", defaultValue = "${project.version}")
private String bomVersion;

@Parameter(property = "outputFile", defaultValue = "${project.build.directory}/extensions.json")
private File outputFile;

@Component
private RepositorySystem repoSystem;

@Parameter(defaultValue = "${repositorySystemSession}", readonly = true)
private RepositorySystemSession repoSession;

@Parameter(defaultValue = "${project.remoteProjectRepositories}", readonly = true, required = true)
private List<RemoteRepository> repos;

@Component
private MavenProject project;

public GenerateExtensionsJsonMojo() {
MojoLogger.logSupplier = this::getLog;
}

@Override
public void execute() throws MojoExecutionException, MojoFailureException {

final DefaultArtifact bomArtifact = new DefaultArtifact(bomGroupId, bomArtifactId, "", "pom", bomVersion);
debug("Generating catalog of extensions for %s", bomArtifact);

final List<Dependency> deps;
try {
deps = repoSystem
.readArtifactDescriptor(repoSession,
new ArtifactDescriptorRequest().setRepositories(repos).setArtifact(bomArtifact))
.getManagedDependencies();
} catch (ArtifactDescriptorException e) {
throw new MojoExecutionException("Failed to read descriptor of " + bomArtifact, e);
}
if (deps.isEmpty()) {
getLog().warn("BOM " + bomArtifact + " does not include any dependency");
return;
}

/*
* final List<ArtifactRequest> requests = deps.stream()
* .map(d -> new ArtifactRequest()
* .setArtifact(d.getArtifact())
* .setRepositories(repos))
* .collect(Collectors.toList());
* final List<ArtifactResult> resolvedDeps;
* try {
* resolvedDeps = repoSystem.resolveArtifacts(repoSession, requests);
* } catch (ArtifactResolutionException e) {
* throw new MojoExecutionException("Failed to resolve dependencies defined in " + bomArtifact, e);
* }
*
* for (ArtifactResult resolved : resolvedDeps) {
* if (!resolved.getArtifact().getExtension().equals("jar")) {
* continue;
* }
* processDependency(resolved.getArtifact().getFile().toPath());
* }
*/

final JsonArrayBuilder extJsonBuilder = Json.createArrayBuilder();
for (Dependency dep : deps) {
if (!dep.getArtifact().getExtension().equals("jar")) {
continue;
}
ArtifactResult resolved = null;
try {
resolved = repoSystem.resolveArtifact(repoSession,
new ArtifactRequest().setRepositories(repos).setArtifact(dep.getArtifact()));
} catch (ArtifactResolutionException e) {
getLog().error("Failed to resolve dependency " + dep.getArtifact() + " defined in " + bomArtifact);
//throw new MojoExecutionException("Failed to resolve dependency " + dep.getArtifact() + " defined in " + bomArtifact, e);
}
if (resolved != null) {
processDependency(resolved.getArtifact(), extJsonBuilder);
}
}

final JsonWriterFactory jsonWriterFactory = Json
.createWriterFactory(Collections.singletonMap(JsonGenerator.PRETTY_PRINTING, true));
try (JsonWriter jsonWriter = jsonWriterFactory.createWriter(new FileOutputStream(outputFile))) {
jsonWriter.writeArray(extJsonBuilder.build());
} catch (IOException e) {
throw new MojoExecutionException("Failed to persist " + outputFile, e);
}
}

private void processDependency(Artifact artifact, JsonArrayBuilder extJsonBuilder) {
final Path path = artifact.getFile().toPath();
try {
if (Files.isDirectory(path)) {
processMetaInfDir(artifact, path.resolve(BootstrapConstants.META_INF), extJsonBuilder);
} else {
try (FileSystem artifactFs = ZipUtils.newFileSystem(path)) {
processMetaInfDir(artifact, artifactFs.getPath(BootstrapConstants.META_INF), extJsonBuilder);
}
}
} catch (Throwable t) {
throw new DeploymentInjectionException("Failed to inject extension deplpyment dependencies", t);
}
}

private boolean processMetaInfDir(Artifact artifact, Path metaInfDir, JsonArrayBuilder extJsonBuilder)
throws BootstrapDependencyProcessingException {
if (!Files.exists(metaInfDir)) {
return false;
}
final Path p = metaInfDir.resolve(BootstrapConstants.DESCRIPTOR_FILE_NAME);
if (!Files.exists(p)) {
return false;
}
processPlatformArtifact(artifact, p, extJsonBuilder);
return true;
}

private void processPlatformArtifact(Artifact artifact, Path descriptor, JsonArrayBuilder extJsonBuilder)
throws BootstrapDependencyProcessingException {
final Properties extProps = resolveDescriptor(descriptor);
if (extProps == null) {
return;
}
debug("Adding Quarkus extension %s", artifact);

final JsonObjectBuilder jsonExtBuilder = Json.createObjectBuilder()
.add(PROP_GROUP_ID, artifact.getGroupId())
.add(PROP_ARTIFACT_ID, artifact.getArtifactId());

addJsonProp(PROP_NAME, extProps, jsonExtBuilder);
addJsonProp(PROP_SHORT_NAME, extProps, jsonExtBuilder);
addJsonProp(PROP_GUIDE, extProps, jsonExtBuilder);

final String labelsStr = extProps.getProperty(PROP_LABELS);
if (labelsStr != null) {
final JsonArrayBuilder jsonArr = Json.createArrayBuilder();
for (String label : labelsStr.split("\\s*,\\s*")) {
jsonArr.add(label);
}
jsonExtBuilder.add(PROP_LABELS, jsonArr.build());
}

extJsonBuilder.add(jsonExtBuilder.build());
}

private static void addJsonProp(String name, Properties props, JsonObjectBuilder builder) {
final String value = props.getProperty(name);
if (value == null) {
return;
}
builder.add(name, value);
}

private Properties resolveDescriptor(final Path path) throws BootstrapDependencyProcessingException {
final Properties rtProps;
if (!Files.exists(path)) {
// not a platform artifact
return null;
}
rtProps = new Properties();
try (BufferedReader reader = Files.newBufferedReader(path)) {
rtProps.load(reader);
} catch (IOException e) {
throw new BootstrapDependencyProcessingException("Failed to load " + path, e);
}
return rtProps;
}

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));
}
}
25 changes: 25 additions & 0 deletions extensions/arc/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,31 @@
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-bootstrap-maven-plugin</artifactId>
<executions>
<execution>
<id>generate-extension-descriptor</id>
<configuration>
<properties>
<property>
<name>name</name>
<value>Arc</value>
</property>
<property>
<name>shortName</name>
<value>CDI</value>
</property>
<property>
<name>guide</name>
<value>https://quarkus.io/guides/cdi-reference</value>
</property>
<property>
<name>labels</name>
<value>arc, cdi, dependency-injection, di</value>
</property>
</properties>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,14 @@ public class ExtensionDescriptorMojo extends AbstractMojo {
@Parameter(required = true)
private String deployment;

@Parameter(required = false)
private Properties properties = new Properties();

@Override
public void execute() throws MojoExecutionException {

final Properties props = new Properties();
props.putAll(properties);
props.setProperty(BootstrapConstants.PROP_DEPLOYMENT_ARTIFACT, deployment);

final Path output = outputDirectory.toPath().resolve(BootstrapConstants.META_INF);
Expand Down

0 comments on commit c80e58e

Please sign in to comment.