Skip to content

Commit 168fb3f

Browse files
authored
Build pdf from AsciiDoc and assembly for Antora (#122)
* Build pdf from AsciiDoc and assembly for Antora * remove table number from partials * remove table number from partials
1 parent 2c1cd99 commit 168fb3f

File tree

19 files changed

+902
-12
lines changed

19 files changed

+902
-12
lines changed

commons/doc-maven-plugin/pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* information: "Portions copyright [year] [name of copyright owner]".
1414
*
1515
* Copyright 2012-2015 ForgeRock AS.
16+
* Portions copyright 2024 3A Systems LLC.
1617
-->
1718
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
1819
<modelVersion>4.0.0</modelVersion>
@@ -131,6 +132,11 @@
131132
<artifactId>commons-io</artifactId>
132133
</dependency>
133134

135+
<dependency>
136+
<groupId>org.apache.commons</groupId>
137+
<artifactId>commons-text</artifactId>
138+
</dependency>
139+
134140
<dependency>
135141
<groupId>org.codehaus.plexus</groupId>
136142
<artifactId>plexus-utils</artifactId>
@@ -153,6 +159,10 @@
153159
<artifactId>mojo-executor</artifactId>
154160
<version>2.2.0</version>
155161
</dependency>
162+
<dependency>
163+
<groupId>org.asciidoctor</groupId>
164+
<artifactId>asciidoctorj</artifactId>
165+
</dependency>
156166

157167
<!-- Runtime -->
158168

commons/doc-maven-plugin/src/main/java/org/forgerock/doc/maven/PreProcessMojo.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public void execute() throws MojoExecutionException, MojoFailureException {
7272

7373
if (!doUsePreProcessedSources()) { // Sources require pre-processing.
7474
new CommonContent(this).execute();
75-
new AsciidocToDocBook(this).execute();
75+
//new AsciidocToDocBook(this).execute();
7676
new JCite(this).execute();
7777
new XCite(this).execute();
7878
new Filter(this).execute();
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* The contents of this file are subject to the terms of the Common Development and
3+
* Distribution License (the License). You may not use this file except in compliance with the
4+
* License.
5+
*
6+
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
7+
* specific language governing permission and limitations under the License.
8+
*
9+
* When distributing Covered Software, include this CDDL Header Notice in each file and include
10+
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
11+
* Header, with the fields enclosed by brackets [] replaced by your own identifying
12+
* information: "Portions copyright [year] [name of copyright owner]".
13+
*
14+
* Copyright 2024 3A Systems LLC.
15+
*/
16+
17+
package org.openidentityplatform.doc.maven;
18+
19+
import org.apache.maven.execution.MavenSession;
20+
import org.apache.maven.plugin.AbstractMojo;
21+
import org.apache.maven.plugin.BuildPluginManager;
22+
import org.apache.maven.plugin.MojoExecutionException;
23+
import org.apache.maven.plugins.annotations.Component;
24+
import org.apache.maven.plugins.annotations.Parameter;
25+
import org.apache.maven.project.MavenProject;
26+
27+
import java.io.File;
28+
import java.util.Arrays;
29+
import java.util.HashSet;
30+
import java.util.List;
31+
import java.util.Set;
32+
import java.util.stream.Collectors;
33+
34+
public abstract class AbstractAsciidocMojo extends AbstractMojo {
35+
36+
@Parameter(property = "project", required = true, readonly = true)
37+
protected MavenProject project;
38+
39+
/**
40+
* The {@code MavenSession} object, which is read-only.
41+
*/
42+
@Parameter(property = "session", required = true, readonly = true)
43+
protected MavenSession session;
44+
45+
@Component
46+
protected BuildPluginManager pluginManager;
47+
48+
49+
/**
50+
* Short name of the project, such as OpenAM, OpenDJ, OpenIDM.
51+
*/
52+
@Parameter(property = "projectName", required = true)
53+
protected String projectName;
54+
55+
/**
56+
* Project version.
57+
*/
58+
@Parameter(property = "projectVersion", required = true)
59+
protected String projectVersion;
60+
61+
/**
62+
* Version for this release.
63+
*/
64+
@Parameter(property = "releaseVersion", required = true)
65+
protected String releaseVersion;
66+
67+
68+
/**
69+
* The project build directory.
70+
*
71+
* <br>
72+
*
73+
* Default: {@code ${project.build.directory}}.
74+
*/
75+
@Parameter(defaultValue = "${project.build.directory}/asciidoc")
76+
protected File buildDirectory;
77+
78+
@Parameter(defaultValue = "${basedir}/src/main/asciidoc")
79+
private File asciidocSourceDirectory;
80+
81+
protected File getAsciidocSourceDirectory() throws MojoExecutionException {
82+
if(asciidocSourceDirectory == null) {
83+
throw new MojoExecutionException("asciidoc sourcer directory should not be empty");
84+
}
85+
return asciidocSourceDirectory;
86+
}
87+
88+
protected File getAsciidocBuildSourceDirectory() throws MojoExecutionException {
89+
return new File(buildDirectory, "/source");
90+
}
91+
92+
93+
@Parameter(property = "documents", required = true)
94+
private List<String> documents;
95+
96+
public static Set<String> ignoreFolders = new HashSet<>(Arrays.asList("partials", "images"));
97+
protected List<String> getDocuments() throws MojoExecutionException {
98+
if(documents == null || documents.size() == 0) {
99+
documents = Arrays.stream(getAsciidocSourceDirectory().listFiles())
100+
.filter(f -> !ignoreFolders.contains(f.getName()))
101+
.map(File::getName).collect(Collectors.toList());
102+
}
103+
if(documents.size() == 0) {
104+
throw new MojoExecutionException("At least one document should be set");
105+
}
106+
return documents;
107+
}
108+
109+
/**
110+
* Base directory for built documentation.
111+
*
112+
* <br>
113+
*
114+
* Value: {@code ${project.build.directory}/antora}
115+
*
116+
* @return The base directory for built documentation.
117+
*/
118+
public File getAntoraOutputDirectory() {
119+
return new File(buildDirectory, "/antora");
120+
}
121+
122+
}
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/*
2+
* The contents of this file are subject to the terms of the Common Development and
3+
* Distribution License (the License). You may not use this file except in compliance with the
4+
* License.
5+
*
6+
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
7+
* specific language governing permission and limitations under the License.
8+
*
9+
* When distributing Covered Software, include this CDDL Header Notice in each file and include
10+
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
11+
* Header, with the fields enclosed by brackets [] replaced by your own identifying
12+
* information: "Portions copyright [year] [name of copyright owner]".
13+
*
14+
* Copyright 2024 3A Systems LLC.
15+
*/
16+
17+
package org.openidentityplatform.doc.maven;
18+
19+
import org.apache.commons.io.FileUtils;
20+
import org.apache.commons.io.FilenameUtils;
21+
import org.apache.commons.text.TextStringBuilder;
22+
import org.apache.maven.plugin.MojoExecutionException;
23+
import org.apache.maven.plugin.MojoFailureException;
24+
import org.apache.maven.plugins.annotations.LifecyclePhase;
25+
import org.apache.maven.plugins.annotations.Mojo;
26+
27+
import java.io.File;
28+
import java.io.IOException;
29+
import java.nio.charset.StandardCharsets;
30+
import java.nio.file.Files;
31+
import java.nio.file.Path;
32+
import java.nio.file.Paths;
33+
import java.util.regex.Matcher;
34+
import java.util.regex.Pattern;
35+
36+
@Mojo(name = "antora", defaultPhase = LifecyclePhase.SITE)
37+
public class AntoraMojo extends AbstractAsciidocMojo {
38+
39+
@Override
40+
public void execute() throws MojoExecutionException, MojoFailureException {
41+
try {
42+
43+
String antoraTarget = getAntoraOutputDirectory().toString();
44+
Path productPath = Paths.get(antoraTarget, "modules");
45+
if(Files.exists(productPath)) {
46+
FileUtils.deleteDirectory(productPath.toFile());
47+
}
48+
Files.createDirectories(productPath);
49+
50+
for(File docDir : getAsciidocBuildSourceDirectory().listFiles()) {
51+
String document = FilenameUtils.getBaseName(docDir.toString());
52+
if(document.equals("images")) {
53+
getLog().info("Copy images to the ROOT module");
54+
copyImagesToRoot(docDir);
55+
continue;
56+
}
57+
if(document.equals("partials")) {
58+
getLog().info("Copy partials to the ROOT module");
59+
copyPartialsToRoot(docDir);
60+
continue;
61+
}
62+
if(!getDocuments().contains(document)) {
63+
getLog().info("Skip document " + document);
64+
continue;
65+
}
66+
getLog().info("Convert document " + document);
67+
convertDocForAntora(productPath, docDir);
68+
}
69+
createIndexForRoot();
70+
} catch (IOException e) {
71+
throw new MojoExecutionException("Error converting to antora: " + e);
72+
}
73+
}
74+
75+
private void convertDocForAntora(Path productPath, File docDir) throws IOException {
76+
77+
Path rootPath = Paths.get(productPath.toString(), "ROOT");
78+
Files.createDirectories(rootPath);
79+
80+
String document = FilenameUtils.getBaseName(docDir.toString());
81+
Path docModulePath = Paths.get(productPath.toString(), document);
82+
Files.createDirectory(docModulePath);
83+
84+
Path docModulePagesPath = Paths.get(docModulePath.toString(), "pages");
85+
Files.createDirectory(docModulePagesPath);
86+
87+
File[] docFiles = docDir.listFiles();
88+
for (File docFile : docFiles) {
89+
String adoc = FileUtils.readFileToString(docFile, StandardCharsets.UTF_8);
90+
if(docFile.getName().equals("index.adoc")) {
91+
int navStartIndex = adoc.indexOf("include::./");
92+
Path indexFilePath = Paths.get(docModulePagesPath.toString(), "index.adoc");
93+
String index = adoc;
94+
index = index.replace("include::./", "* xref:");
95+
FileUtils.writeStringToFile(indexFilePath.toFile(), index, StandardCharsets.UTF_8);
96+
97+
Path navFilePath = Paths.get(docModulePath.toString(), "nav.adoc");
98+
String nav = adoc.substring(navStartIndex);
99+
nav = "* xref:index.adoc[]" + System.lineSeparator() + nav;
100+
nav = nav.replace("include::./", "** xref:");
101+
FileUtils.writeStringToFile(navFilePath.toFile(), nav, StandardCharsets.UTF_8);
102+
} else {
103+
Path convertedFilePath = Paths.get(docModulePagesPath.toString(), docFile.getName());
104+
adoc = ":leveloffset: -1" + System.lineSeparator() + adoc;
105+
adoc = adoc.replace("image::images/", "image::ROOT:");
106+
adoc = adoc.replace("image:images/", "image:ROOT:");
107+
adoc = adoc.replace("include::../partials/", "include::ROOT:partial$");
108+
109+
adoc = convertXrefsToAntora(adoc);
110+
111+
FileUtils.writeStringToFile(convertedFilePath.toFile(), adoc, StandardCharsets.UTF_8);
112+
}
113+
}
114+
}
115+
116+
private String convertXrefsToAntora(String adoc) {
117+
Pattern p = Pattern.compile("xref\\:(.+?)\\[");
118+
119+
Matcher m = p.matcher(adoc);
120+
StringBuilder builder = new StringBuilder();
121+
int i = 0;
122+
while (m.find()) {
123+
builder.append(adoc, i, m.start());
124+
String url = m.group(1);
125+
url = url.replace("../", "");
126+
url = url.replace("/", ":");
127+
128+
builder.append("xref:").append(url).append("[");
129+
130+
i = m.end();
131+
}
132+
builder.append(adoc.substring(i));
133+
return builder.toString();
134+
}
135+
136+
private void createIndexForRoot() throws IOException, MojoExecutionException {
137+
Path rootPath = getRootModulePath();
138+
Path pagesPath = Paths.get(rootPath.toString(), "pages");
139+
if(!Files.exists(pagesPath)) {
140+
Files.createDirectory(pagesPath);
141+
}
142+
Path indexFilePath = Paths.get(pagesPath.toString(), "index.adoc");
143+
TextStringBuilder builder = new TextStringBuilder();
144+
builder.append("= ").append(projectName).appendln(" Documentation");
145+
builder.appendNewLine();
146+
for(String doc : getDocuments()) {
147+
builder.append("* xref:").append(doc).appendln(":index.adoc[]");
148+
}
149+
builder.appendNewLine();
150+
151+
FileUtils.writeStringToFile(indexFilePath.toFile(), builder.toString(), StandardCharsets.UTF_8);
152+
153+
}
154+
155+
private void copyImagesToRoot(File docDir) throws IOException {
156+
Path rootPath = getRootModulePath();
157+
Path rootImagesPath = Paths.get(rootPath.toString(), "images");
158+
FileUtils.copyDirectory(docDir, rootImagesPath.toFile());
159+
}
160+
private void copyPartialsToRoot(File docDir) throws IOException {
161+
Path rootPath = getRootModulePath();
162+
Path rootPartialsPath = Paths.get(rootPath.toString(), "partials");
163+
FileUtils.copyDirectory(docDir, rootPartialsPath.toFile());
164+
}
165+
166+
private Path getRootModulePath() throws IOException {
167+
String antoraTarget = getAntoraOutputDirectory().toString();
168+
return Paths.get(antoraTarget, "modules", "ROOT");
169+
}
170+
}

0 commit comments

Comments
 (0)