/*
* #%L
* Wisdom-Framework
* %%
* Copyright (C) 2013 - 2014 Wisdom Framework
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package org.wisdom.asciidoc;
import com.google.common.collect.ImmutableList;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.AndFileFilter;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.NotFileFilter;
import org.apache.commons.io.filefilter.WildcardFileFilter;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.asciidoctor.*;
import org.wisdom.maven.Constants;
import org.wisdom.maven.WatchingException;
import org.wisdom.maven.mojos.AbstractWisdomWatcherMojo;
import org.wisdom.maven.utils.WatcherUtils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.asciidoctor.Asciidoctor.Factory.create;
/**
* Compiles Asciidoc files to HTML documents.
*/
@Mojo(name = "compile-asciidoc", threadSafe = false,
requiresDependencyResolution = ResolutionScope.COMPILE,
requiresProject = true,
defaultPhase = LifecyclePhase.COMPILE)
public class AsciidocMojo extends AbstractWisdomWatcherMojo implements Constants {
@Parameter(property = Options.ATTRIBUTES, required = false)
protected Map<String, Object> attributes = new HashMap<>();
@Parameter(property = Options.BACKEND, defaultValue = "html5", required = true)
protected String backend = "";
@Parameter(property = Options.COMPACT, required = false)
protected boolean compact = false;
@Parameter(property = Options.DOCTYPE, defaultValue = "article", required = true)
protected String doctype;
@Parameter(property = Options.ERUBY, required = false, defaultValue = "erb")
protected String eruby = "erb";
@Parameter(property = "headerFooter", required = false, defaultValue = "true")
protected boolean headerFooter = true;
@Parameter(property = "templateDir", required = false)
protected File templateDir;
@Parameter(property = "templateEngine", required = false)
protected String templateEngine;
@Parameter(property = "imagesDir", required = false)
protected String imagesDir = "images"; // use a string because otherwise html doc uses absolute path
@Parameter(property = "sourceHighlighter", required = false)
protected String sourceHighlighter = "";
@Parameter(property = "extensions")
protected List<String> extensions = new ArrayList<>();
@Parameter(property = "embedAssets")
protected boolean embedAssets = false;
@Parameter
protected String stylesheet;
@Parameter
protected String stylesheetDir;
/**
* List of ant-style patterns used to specify the asciidoc file that should be included when compiling.
*/
@Parameter
protected String[] includes;
/**
* List of ant-style patterns used to specify the asciidoc file that should **NOT** be included when
* compiling.
*/
protected String[] excludes;
Asciidoctor instance;
/**
* Enable or disable the watch mode, enabled by default.
*/
@Parameter(defaultValue = "true")
private boolean watch;
/**
* Compiles Asciidoc files from the internal and external assets to HTML.
*
* @throws MojoExecutionException if the processing failed
*/
public void execute()
throws MojoExecutionException {
if (! watch) {
removeFromWatching();
}
if (extensions == null || extensions.isEmpty()) {
extensions = ImmutableList.of("ad", "asciidoc", "adoc");
}
if (instance == null) {
instance = getAsciidoctorInstance();
}
final OptionsBuilder optionsBuilderExternals = OptionsBuilder.options().compact(compact)
.safe(SafeMode.UNSAFE).eruby(eruby).backend(backend).docType(doctype).headerFooter(headerFooter).inPlace(true);
final OptionsBuilder optionsBuilderInternals = OptionsBuilder.options().compact(compact)
.safe(SafeMode.UNSAFE).eruby(eruby).backend(backend).docType(doctype).headerFooter(headerFooter).inPlace(true);
if (templateEngine != null) {
optionsBuilderExternals.templateEngine(templateEngine);
optionsBuilderInternals.templateEngine(templateEngine);
}
if (templateDir != null) {
optionsBuilderExternals.templateDir(templateDir);
optionsBuilderInternals.templateDir(templateDir);
}
if (sourceHighlighter != null) {
attributes.put("source-highlighter", sourceHighlighter);
}
if (embedAssets) {
attributes.put("linkcss!", true);
attributes.put("data-uri", true);
}
if (imagesDir != null) {
attributes.put("imagesdir", imagesDir);
}
if (stylesheet != null) {
attributes.put(Attributes.STYLESHEET_NAME, stylesheet);
attributes.put(Attributes.LINK_CSS, true);
}
if (stylesheetDir != null) {
attributes.put(Attributes.STYLES_DIR, stylesheetDir);
}
optionsBuilderExternals.attributes(attributes);
optionsBuilderInternals.attributes(attributes);
IOFileFilter filter = null;
if (includes != null && includes.length != 0) {
filter = new WildcardFileFilter(includes);
if (excludes != null && excludes.length != 0) {
filter = new AndFileFilter(filter, new NotFileFilter(new WildcardFileFilter(excludes)));
}
}
try {
for (File file : getResources(extensions)) {
if (filter == null || filter.accept(file)) {
renderFile(optionsBuilderExternals.asMap(), file);
}
}
} catch (IOException e) {
throw new MojoExecutionException("Error while compiling AsciiDoc file", e);
}
}
protected Asciidoctor getAsciidoctorInstance() throws MojoExecutionException {
return create(this.getClass().getClassLoader());
}
protected void renderFile(Map<String, Object> options, File f) throws IOException {
File filtered = getFilteredVersion(f);
boolean unfiltered;
if (filtered == null) {
// It was not copied.
getLog().error("Cannot find the filtered version of " + f.getAbsolutePath() + ", " +
"using unprocessed file.");
filtered = f;
unfiltered = true;
} else {
// It was copied.
unfiltered = false;
}
instance.renderFile(filtered, options);
// Move the file to the expected place if not filtered
if (unfiltered) {
String name = filtered.getName().substring(0, filtered.getName().lastIndexOf(".")) + ".html";
File output = new File(filtered.getParentFile(), name);
if (output.isFile()) {
// Move...
File finalFile = getOutputFile(filtered, "html");
FileUtils.moveFile(output, finalFile);
} else {
getLog().error("Cannot find the output file for " + filtered.getAbsolutePath());
}
}
}
@Override
public boolean accept(File file) {
return WatcherUtils.hasExtension(file, extensions);
}
@Override
public boolean fileCreated(File file) throws WatchingException {
try {
execute();
} catch (MojoExecutionException e) {
throw new WatchingException(e.getMessage(), file, e);
}
return true;
}
@Override
public boolean fileUpdated(File file) throws WatchingException {
return fileCreated(file);
}
@Override
public boolean fileDeleted(File file) throws WatchingException {
File output = getOutputFile(file, "html");
FileUtils.deleteQuietly(output);
return fileCreated(file);
}
}