Remove old Painless doc generator (#43404)

This removes the previous Painless API Doc Generator prior to contexts 
existing. It has been replaced with the new doc generator that uses the 
documentation rest API.
This commit is contained in:
Jack Conradson 2019-06-20 08:48:01 -07:00
parent a8a81200d0
commit 7ef62a6cbc
1 changed files with 0 additions and 451 deletions

View File

@ -1,451 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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.
*/
package org.elasticsearch.painless;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.core.internal.io.IOUtils;
import org.elasticsearch.painless.lookup.PainlessClass;
import org.elasticsearch.painless.lookup.PainlessConstructor;
import org.elasticsearch.painless.lookup.PainlessField;
import org.elasticsearch.painless.lookup.PainlessLookup;
import org.elasticsearch.painless.lookup.PainlessLookupBuilder;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.lookup.PainlessMethod;
import org.elasticsearch.painless.lookup.def;
import org.elasticsearch.painless.spi.Whitelist;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Modifier;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import static java.util.Comparator.comparing;
/**
* Generates an API reference from the method and type whitelists in {@link PainlessLookup}.
*/
public class PainlessDocGenerator {
private static final PainlessLookup PAINLESS_LOOKUP = PainlessLookupBuilder.buildFromWhitelists(Whitelist.BASE_WHITELISTS);
private static final Logger logger = LogManager.getLogger(PainlessDocGenerator.class);
private static final Comparator<PainlessField> FIELD_NAME = comparing(f -> f.javaField.getName());
private static final Comparator<PainlessMethod> METHOD_NAME = comparing(m -> m.javaMethod.getName());
private static final Comparator<PainlessMethod> METHOD_NUMBER_OF_PARAMS = comparing(m -> m.typeParameters.size());
private static final Comparator<PainlessConstructor> CONSTRUCTOR_NUMBER_OF_PARAMS = comparing(m -> m.typeParameters.size());
public static void main(String[] args) throws IOException {
Path apiRootPath = PathUtils.get(args[0]);
// Blow away the last execution and recreate it from scratch
IOUtils.rm(apiRootPath);
Files.createDirectories(apiRootPath);
Path indexPath = apiRootPath.resolve("index.asciidoc");
logger.info("Starting to write [index.asciidoc]");
try (PrintStream indexStream = new PrintStream(
Files.newOutputStream(indexPath, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE),
false, StandardCharsets.UTF_8.name())) {
emitGeneratedWarning(indexStream);
List<Class<?>> classes = PAINLESS_LOOKUP.getClasses().stream().sorted(
Comparator.comparing(Class::getCanonicalName)).collect(Collectors.toList());
for (Class<?> clazz : classes) {
PainlessClass struct = PAINLESS_LOOKUP.lookupPainlessClass(clazz);
String canonicalClassName = PainlessLookupUtility.typeToCanonicalTypeName(clazz);
if (clazz.isPrimitive()) {
// Primitives don't have methods to reference
continue;
}
if (clazz == def.class) {
// def is special but doesn't have any methods all of its own.
continue;
}
indexStream.print("include::");
indexStream.print(canonicalClassName);
indexStream.println(".asciidoc[]");
Path typePath = apiRootPath.resolve(canonicalClassName + ".asciidoc");
logger.info("Writing [{}.asciidoc]", canonicalClassName);
try (PrintStream typeStream = new PrintStream(
Files.newOutputStream(typePath, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE),
false, StandardCharsets.UTF_8.name())) {
emitGeneratedWarning(typeStream);
typeStream.print("[[");
emitAnchor(typeStream, clazz);
typeStream.print("]]++");
typeStream.print(canonicalClassName);
typeStream.println("++::");
Consumer<PainlessField> documentField = field -> PainlessDocGenerator.documentField(typeStream, field);
Consumer<PainlessMethod> documentMethod = method -> PainlessDocGenerator.documentMethod(typeStream, method);
Consumer<PainlessConstructor> documentConstructor =
constructor -> PainlessDocGenerator.documentConstructor(typeStream, constructor);
struct.staticFields.values().stream().sorted(FIELD_NAME).forEach(documentField);
struct.fields.values().stream().sorted(FIELD_NAME).forEach(documentField);
struct.staticMethods.values().stream().sorted(
METHOD_NAME.thenComparing(METHOD_NUMBER_OF_PARAMS)).forEach(documentMethod);
struct.constructors.values().stream().sorted(CONSTRUCTOR_NUMBER_OF_PARAMS).forEach(documentConstructor);
Map<String, Class<?>> inherited = new TreeMap<>();
struct.methods.values().stream().sorted(METHOD_NAME.thenComparing(METHOD_NUMBER_OF_PARAMS)).forEach(method -> {
if (method.targetClass == clazz) {
documentMethod(typeStream, method);
} else {
inherited.put(canonicalClassName, method.targetClass);
}
});
if (false == inherited.isEmpty()) {
typeStream.print("* Inherits methods from ");
boolean first = true;
for (Class<?> inheritsFrom : inherited.values()) {
if (first) {
first = false;
} else {
typeStream.print(", ");
}
typeStream.print("++");
emitStruct(typeStream, inheritsFrom);
typeStream.print("++");
}
typeStream.println();
}
}
}
}
logger.info("Done writing [index.asciidoc]");
}
private static void documentField(PrintStream stream, PainlessField field) {
stream.print("** [[");
emitAnchor(stream, field);
stream.print("]]");
if (Modifier.isStatic(field.javaField.getModifiers())) {
stream.print("static ");
}
emitType(stream, field.typeParameter);
stream.print(' ');
String javadocRoot = javadocRoot(field);
emitJavadocLink(stream, javadocRoot, field);
stream.print('[');
stream.print(field.javaField.getName());
stream.print(']');
if (javadocRoot.equals("java8")) {
stream.print(" (");
emitJavadocLink(stream, "java9", field);
stream.print("[java 9])");
}
stream.println();
}
/**
* Document a constructor.
*/
private static void documentConstructor(PrintStream stream, PainlessConstructor constructor) {
stream.print("* ++[[");
emitAnchor(stream, constructor);
stream.print("]]");
String javadocRoot = javadocRoot(constructor.javaConstructor.getDeclaringClass());
emitJavadocLink(stream, javadocRoot, constructor);
stream.print('[');
stream.print(constructorName(constructor));
stream.print("](");
boolean first = true;
for (Class<?> arg : constructor.typeParameters) {
if (first) {
first = false;
} else {
stream.print(", ");
}
emitType(stream, arg);
}
stream.print(")++");
if (javadocRoot.equals("java8")) {
stream.print(" (");
emitJavadocLink(stream, "java9", constructor);
stream.print("[java 9])");
}
stream.println();
}
/**
* Document a method.
*/
private static void documentMethod(PrintStream stream, PainlessMethod method) {
stream.print("* ++[[");
emitAnchor(stream, method);
stream.print("]]");
if (method.targetClass == method.javaMethod.getDeclaringClass() && Modifier.isStatic(method.javaMethod.getModifiers())) {
stream.print("static ");
}
emitType(stream, method.returnType);
stream.print(' ');
String javadocRoot = javadocRoot(method);
emitJavadocLink(stream, javadocRoot, method);
stream.print('[');
stream.print(methodName(method));
stream.print("](");
boolean first = true;
for (Class<?> arg : method.typeParameters) {
if (first) {
first = false;
} else {
stream.print(", ");
}
emitType(stream, arg);
}
stream.print(")++");
if (javadocRoot.equals("java8")) {
stream.print(" (");
emitJavadocLink(stream, "java9", method);
stream.print("[java 9])");
}
stream.println();
}
/**
* Anchor text for a {@link PainlessClass}.
*/
private static void emitAnchor(PrintStream stream, Class<?> clazz) {
stream.print("painless-api-reference-");
stream.print(PainlessLookupUtility.typeToCanonicalTypeName(clazz).replace('.', '-'));
}
/**
* Anchor text for a {@link PainlessConstructor}.
*/
private static void emitAnchor(PrintStream stream, PainlessConstructor constructor) {
emitAnchor(stream, constructor.javaConstructor.getDeclaringClass());
stream.print('-');
stream.print(constructorName(constructor));
stream.print('-');
stream.print(constructor.typeParameters.size());
}
/**
* Anchor text for a {@link PainlessMethod}.
*/
private static void emitAnchor(PrintStream stream, PainlessMethod method) {
emitAnchor(stream, method.targetClass);
stream.print('-');
stream.print(methodName(method));
stream.print('-');
stream.print(method.typeParameters.size());
}
/**
* Anchor text for a {@link PainlessField}.
*/
private static void emitAnchor(PrintStream stream, PainlessField field) {
emitAnchor(stream, field.javaField.getDeclaringClass());
stream.print('-');
stream.print(field.javaField.getName());
}
private static String constructorName(PainlessConstructor constructor) {
return PainlessLookupUtility.typeToCanonicalTypeName(constructor.javaConstructor.getDeclaringClass());
}
private static String methodName(PainlessMethod method) {
return PainlessLookupUtility.typeToCanonicalTypeName(method.targetClass);
}
/**
* Emit a {@link Class}. If the type is primitive or an array of primitives this just emits the name of the type. Otherwise this emits
an internal link with the text.
*/
private static void emitType(PrintStream stream, Class<?> clazz) {
emitStruct(stream, clazz);
while ((clazz = clazz.getComponentType()) != null) {
stream.print("[]");
}
}
/**
* Emit a {@link PainlessClass}. If the {@linkplain PainlessClass} is primitive or def this just emits the name of the struct.
* Otherwise this emits an internal link with the name.
*/
private static void emitStruct(PrintStream stream, Class<?> clazz) {
String canonicalClassName = PainlessLookupUtility.typeToCanonicalTypeName(clazz);
if (false == clazz.isPrimitive() && clazz != def.class) {
stream.print("<<");
emitAnchor(stream, clazz);
stream.print(',');
stream.print(canonicalClassName);
stream.print(">>");
} else {
stream.print(canonicalClassName);
}
}
/**
* Emit an external link to Javadoc for a {@link PainlessMethod}.
*
* @param root name of the root uri variable
*/
private static void emitJavadocLink(PrintStream stream, String root, PainlessConstructor constructor) {
stream.print("link:{");
stream.print(root);
stream.print("-javadoc}/");
stream.print(classUrlPath(constructor.javaConstructor.getDeclaringClass()));
stream.print(".html#");
stream.print(constructorName(constructor));
stream.print("%2D");
boolean first = true;
for (Class<?> clazz: constructor.typeParameters) {
if (first) {
first = false;
} else {
stream.print("%2D");
}
stream.print(clazz.getName());
if (clazz.isArray()) {
stream.print(":A");
}
}
stream.print("%2D");
}
/**
* Emit an external link to Javadoc for a {@link PainlessMethod}.
*
* @param root name of the root uri variable
*/
private static void emitJavadocLink(PrintStream stream, String root, PainlessMethod method) {
stream.print("link:{");
stream.print(root);
stream.print("-javadoc}/");
stream.print(classUrlPath(method.javaMethod.getDeclaringClass()));
stream.print(".html#");
stream.print(methodName(method));
stream.print("%2D");
boolean first = true;
if (method.targetClass != method.javaMethod.getDeclaringClass()) {
first = false;
stream.print(method.javaMethod.getDeclaringClass().getName());
}
for (Class<?> clazz: method.typeParameters) {
if (first) {
first = false;
} else {
stream.print("%2D");
}
stream.print(clazz.getName());
if (clazz.isArray()) {
stream.print(":A");
}
}
stream.print("%2D");
}
/**
* Emit an external link to Javadoc for a {@link PainlessField}.
*
* @param root name of the root uri variable
*/
private static void emitJavadocLink(PrintStream stream, String root, PainlessField field) {
stream.print("link:{");
stream.print(root);
stream.print("-javadoc}/");
stream.print(classUrlPath(field.javaField.getDeclaringClass()));
stream.print(".html#");
stream.print(field.javaField.getName());
}
/**
* Pick the javadoc root for a {@link PainlessMethod}.
*/
private static String javadocRoot(PainlessMethod method) {
if (method.targetClass != method.javaMethod.getDeclaringClass()) {
return "painless";
}
return javadocRoot(method.targetClass);
}
/**
* Pick the javadoc root for a {@link PainlessField}.
*/
private static String javadocRoot(PainlessField field) {
return javadocRoot(field.javaField.getDeclaringClass());
}
/**
* Pick the javadoc root for a {@link Class}.
*/
private static String javadocRoot(Class<?> clazz) {
String classPackage = clazz.getPackage().getName();
if (classPackage.startsWith("java")) {
return "java8";
}
if (classPackage.startsWith("org.elasticsearch.painless")) {
return "painless";
}
if (classPackage.startsWith("org.elasticsearch")) {
return "elasticsearch";
}
if (classPackage.startsWith("org.joda.time")) {
return "joda-time";
}
if (classPackage.startsWith("org.apache.lucene")) {
return "lucene-core";
}
throw new IllegalArgumentException("Unrecognized package: " + classPackage);
}
private static void emitGeneratedWarning(PrintStream stream) {
stream.println("////");
stream.println("Automatically generated by PainlessDocGenerator. Do not edit.");
stream.println("Rebuild by running `gradle generatePainlessApi`.");
stream.println("////");
stream.println();
}
private static String classUrlPath(Class<?> clazz) {
return clazz.getName().replace('.', '/').replace('$', '.');
}
}