Files
gerrit/lib/asciidoctor/java/AsciiDoctor.java
Hector Oswaldo Caballero db21e3add0 Replace FileInputStream and FileOutputStream with static Files methods
FileInputStream and FileOutputStream rely on finalize() method to ensure
resources are closed. This implies they are added to the finalizer queue
which causes additional work for the JVM GC process.

This is an open bug on the OpenJDK [1] and the recommended workaround is
to use the Files.newInputStream and Files.newOutputStream static methods
instead.

[1] https://bugs.openjdk.java.net/browse/JDK-8080225

Change-Id: I3cef6fcf198dde2be7cd15bded8d2fa247177654
2017-05-10 00:10:52 +00:00

217 lines
6.7 KiB
Java

// Copyright (C) 2013 The Android Open Source Project
//
// 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.
import com.google.common.io.ByteStreams;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.asciidoctor.Asciidoctor;
import org.asciidoctor.AttributesBuilder;
import org.asciidoctor.Options;
import org.asciidoctor.OptionsBuilder;
import org.asciidoctor.SafeMode;
import org.asciidoctor.internal.JRubyAsciidoctor;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option;
public class AsciiDoctor {
private static final String DOCTYPE = "article";
private static final String ERUBY = "erb";
private static final String REVNUMBER_NAME = "revnumber";
@Option(name = "-b", usage = "set output format backend")
private String backend = "html5";
@Option(name = "-z", usage = "output zip file")
private String zipFile;
@Option(name = "--in-ext", usage = "extension for input files")
private String inExt = ".txt";
@Option(name = "--out-ext", usage = "extension for output files")
private String outExt = ".html";
@Option(name = "--base-dir", usage = "base directory")
private File basedir;
@Option(name = "--tmp", usage = "temporary output path")
private File tmpdir;
@Option(name = "--mktmp", usage = "create a temporary output path")
private boolean mktmp;
@Option(name = "-a", usage = "a list of attributes, in the form key or key=value pair")
private List<String> attributes = new ArrayList<>();
@Option(
name = "--bazel",
usage = "bazel mode: generate multiple output files instead of a single zip file"
)
private boolean bazel;
@Option(name = "--revnumber-file", usage = "the file contains revnumber string")
private File revnumberFile;
@Argument(usage = "input files")
private List<String> inputFiles = new ArrayList<>();
private String revnumber;
public static String mapInFileToOutFile(String inFile, String inExt, String outExt) {
String basename = new File(inFile).getName();
if (basename.endsWith(inExt)) {
basename = basename.substring(0, basename.length() - inExt.length());
} else {
// Strip out the last extension
int pos = basename.lastIndexOf('.');
if (pos > 0) {
basename = basename.substring(0, pos);
}
}
return basename + outExt;
}
private Options createOptions(File base, File outputFile) {
OptionsBuilder optionsBuilder = OptionsBuilder.options();
optionsBuilder
.backend(backend)
.docType(DOCTYPE)
.eruby(ERUBY)
.safe(SafeMode.UNSAFE)
.baseDir(base)
.toFile(outputFile);
AttributesBuilder attributesBuilder = AttributesBuilder.attributes();
attributesBuilder.attributes(getAttributes());
if (revnumber != null) {
attributesBuilder.attribute(REVNUMBER_NAME, revnumber);
}
optionsBuilder.attributes(attributesBuilder.get());
return optionsBuilder.get();
}
private Map<String, Object> getAttributes() {
Map<String, Object> attributeValues = new HashMap<>();
for (String attribute : attributes) {
int equalsIndex = attribute.indexOf('=');
if (equalsIndex > -1) {
String name = attribute.substring(0, equalsIndex);
String value = attribute.substring(equalsIndex + 1, attribute.length());
attributeValues.put(name, value);
} else {
attributeValues.put(attribute, "");
}
}
return attributeValues;
}
private void invoke(String... parameters) throws IOException {
CmdLineParser parser = new CmdLineParser(this);
try {
parser.parseArgument(parameters);
if (inputFiles.isEmpty()) {
throw new CmdLineException(parser, "asciidoctor: FAILED: input file missing");
}
} catch (CmdLineException e) {
System.err.println(e.getMessage());
parser.printUsage(System.err);
System.exit(1);
return;
}
if (revnumberFile != null) {
try (BufferedReader reader = new BufferedReader(new FileReader(revnumberFile))) {
revnumber = reader.readLine();
}
}
if (mktmp) {
tmpdir = Files.createTempDirectory("asciidoctor-").toFile();
}
if (bazel) {
renderFiles(inputFiles, null);
} else {
try (ZipOutputStream zip = new ZipOutputStream(Files.newOutputStream(Paths.get(zipFile)))) {
renderFiles(inputFiles, zip);
File[] cssFiles =
tmpdir.listFiles(
new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".css");
}
});
for (File css : cssFiles) {
zipFile(css, css.getName(), zip);
}
}
}
}
private void renderFiles(List<String> inputFiles, ZipOutputStream zip) throws IOException {
Asciidoctor asciidoctor = JRubyAsciidoctor.create();
for (String inputFile : inputFiles) {
String outName = mapInFileToOutFile(inputFile, inExt, outExt);
File out = bazel ? new File(outName) : new File(tmpdir, outName);
if (!bazel) {
out.getParentFile().mkdirs();
}
File input = new File(inputFile);
Options options = createOptions(basedir != null ? basedir : input.getParentFile(), out);
asciidoctor.renderFile(input, options);
if (zip != null) {
zipFile(out, outName, zip);
}
}
}
public static void zipFile(File file, String name, ZipOutputStream zip) throws IOException {
zip.putNextEntry(new ZipEntry(name));
try (InputStream input = Files.newInputStream(file.toPath())) {
ByteStreams.copy(input, zip);
}
zip.closeEntry();
}
public static void main(String[] args) {
try {
new AsciiDoctor().invoke(args);
} catch (IOException e) {
System.err.println(e.getMessage());
System.exit(1);
}
}
}