
io.quarkus.docs.generation.AllConfigGenerator Maven / Gradle / Ivy
package io.quarkus.docs.generation;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.resolution.ArtifactRequest;
import org.eclipse.aether.resolution.ArtifactResult;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import io.quarkus.annotation.processor.generate_doc.ConfigDocGeneratedOutput;
import io.quarkus.annotation.processor.generate_doc.ConfigDocItem;
import io.quarkus.annotation.processor.generate_doc.ConfigDocItemScanner;
import io.quarkus.annotation.processor.generate_doc.ConfigDocSection;
import io.quarkus.annotation.processor.generate_doc.ConfigDocWriter;
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;
public class AllConfigGenerator {
public static void main(String[] args) throws BootstrapMavenException, IOException {
if (args.length != 2) {
// exit 1 will break Maven
throw new IllegalArgumentException("Usage: ");
}
String version = args[0];
String extensionFile = args[1];
// This is where we produce the entire list of extensions
File jsonFile = new File(extensionFile);
if (!jsonFile.exists()) {
System.err.println("WARNING: could not generate all-config file because extensions list is missing: " + jsonFile);
// exit 0 will break Maven
return;
}
ObjectMapper mapper = new ObjectMapper()
.enable(JsonParser.Feature.ALLOW_COMMENTS)
.enable(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS)
.setPropertyNamingStrategy(PropertyNamingStrategy.KEBAB_CASE);
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);
// now get all the listed extension jars via Maven
List requests = new ArrayList<>(extensionJson.extensions.size());
Map extensionsByGav = new HashMap<>();
Map extensionsByConfigRoots = new HashMap<>();
for (Extension extension : extensionJson.extensions) {
ArtifactRequest request = new ArtifactRequest();
Artifact artifact = new DefaultArtifact(extension.groupId, extension.artifactId, "jar", version);
request.setArtifact(artifact);
requests.add(request);
// record the extension for this GAV
extensionsByGav.put(extension.groupId + ":" + extension.artifactId, extension);
}
// examine all the extension jars
List deploymentRequests = new ArrayList<>(extensionJson.extensions.size());
for (ArtifactResult result : resolver.resolve(requests)) {
Artifact artifact = result.getArtifact();
// which extension was this for?
Extension extension = extensionsByGav.get(artifact.getGroupId() + ":" + artifact.getArtifactId());
try (ZipFile zf = new ZipFile(artifact.getFile())) {
// collect all its config roots
collectConfigRoots(zf, extension, extensionsByConfigRoots);
// see if it has a deployment artifact we need to load
ZipEntry entry = zf.getEntry("META-INF/quarkus-extension.properties");
if (entry != null) {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(zf.getInputStream(entry), StandardCharsets.UTF_8))) {
Properties properties = new Properties();
properties.load(reader);
String deploymentGav = (String) properties.get("deployment-artifact");
// if it has one, load it
if (deploymentGav != null) {
ArtifactRequest request = new ArtifactRequest();
Artifact deploymentArtifact = new DefaultArtifact(deploymentGav);
request.setArtifact(deploymentArtifact);
deploymentRequests.add(request);
// tie this artifact to its extension
extensionsByGav.put(deploymentArtifact.getGroupId() + ":" + deploymentArtifact.getArtifactId(),
extension);
}
}
}
}
}
// now examine all the extension deployment jars
for (ArtifactResult result : resolver.resolve(deploymentRequests)) {
Artifact artifact = result.getArtifact();
// which extension was this for?
Extension extension = extensionsByGav.get(artifact.getGroupId() + ":" + artifact.getArtifactId());
try (ZipFile zf = new ZipFile(artifact.getFile())) {
// collect all its config roots
collectConfigRoots(zf, extension, extensionsByConfigRoots);
}
}
// load all the config items per config root
ConfigDocItemScanner configDocItemScanner = new ConfigDocItemScanner();
Map> docItemsByConfigRoots = configDocItemScanner
.loadAllExtensionsConfigurationItems();
Map artifactIdsByName = new HashMap<>();
ConfigDocWriter configDocWriter = new ConfigDocWriter();
// build a list of sorted config items by extension
List allItems = new ArrayList<>();
SortedMap> sortedConfigItemsByExtension = new TreeMap<>();
// Temporary fix for https://github.com/quarkusio/quarkus/issues/5214 until we figure out how to fix it
Extension openApi = extensionsByGav.get("io.quarkus:quarkus-smallrye-openapi");
if (openApi != null) {
extensionsByConfigRoots.put("io.quarkus.smallrye.openapi.common.deployment.SmallRyeOpenApiConfig", openApi);
}
// sort extensions by name, assign their config items based on their config roots
for (Entry entry : extensionsByConfigRoots.entrySet()) {
List items = docItemsByConfigRoots.get(entry.getKey());
if (items != null) {
String extensionName = entry.getValue().name;
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);
}
artifactIdsByName.put(extensionName, entry.getValue().artifactId);
List existingConfigDocItems = sortedConfigItemsByExtension.get(extensionName);
if (existingConfigDocItems != null) {
DocGeneratorUtil.appendConfigItemsIntoExistingOnes(existingConfigDocItems, items);
} else {
ArrayList configItems = new ArrayList<>();
sortedConfigItemsByExtension.put(extensionName, configItems);
configItems.addAll(items);
}
}
}
// now we have all the config items sorted by extension, let's build the entire list
for (Map.Entry> entry : sortedConfigItemsByExtension.entrySet()) {
final List configDocItems = entry.getValue();
// sort the items
DocGeneratorUtil.sort(configDocItems);
// insert a header
ConfigDocSection header = new ConfigDocSection();
header.setShowSection(true);
header.setSectionDetailsTitle(entry.getKey());
header.setAnchorPrefix(artifactIdsByName.get(entry.getKey()));
header.setName(artifactIdsByName.get(entry.getKey()));
allItems.add(new ConfigDocItem(header, null));
// add all the configs for this extension
allItems.addAll(configDocItems);
}
// write our docs
ConfigDocGeneratedOutput allConfigGeneratedOutput = new ConfigDocGeneratedOutput("quarkus-all-config.adoc", true,
allItems,
false);
configDocWriter.writeAllExtensionConfigDocumentation(allConfigGeneratedOutput);
}
private static String guessExtensionNameFromDocumentationFileName(String docFileName) {
// sanitise
if (docFileName.startsWith("quarkus-")) {
docFileName = docFileName.substring(8);
}
if (docFileName.endsWith(".adoc")) {
docFileName = docFileName.substring(0, docFileName.length() - 5);
}
if (docFileName.endsWith("-config")) {
docFileName = docFileName.substring(0, docFileName.length() - 7);
}
if (docFileName.endsWith("-configuration")) {
docFileName = docFileName.substring(0, docFileName.length() - 14);
}
docFileName = docFileName.replace('-', ' ');
return capitalize(docFileName);
}
private static String capitalize(String title) {
char[] chars = title.toCharArray();
boolean capitalize = true;
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
if (Character.isSpaceChar(c)) {
capitalize = true;
continue;
}
if (capitalize) {
if (Character.isLetter(c))
chars[i] = Character.toUpperCase(c);
capitalize = false;
}
}
return new String(chars);
}
private static void collectConfigRoots(ZipFile zf, Extension extension, Map extensionsByConfigRoots)
throws IOException {
ZipEntry entry = zf.getEntry("META-INF/quarkus-config-roots.list");
if (entry != null) {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(zf.getInputStream(entry), StandardCharsets.UTF_8))) {
// make sure we turn $ into . because javadoc-scanned class names are dot-separated
reader.lines().map(String::trim).filter(str -> !str.isEmpty()).map(str -> str.replace('$', '.'))
.forEach(klass -> extensionsByConfigRoots.put(klass, extension));
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy