2020-07-21 03:19:38 -04:00
|
|
|
import javax.annotation.Nullable
|
|
|
|
|
2020-03-11 11:09:26 -04:00
|
|
|
/*
|
|
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
|
|
* this work for additional information regarding copyright ownership.
|
|
|
|
* The ASF 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.
|
|
|
|
*/
|
|
|
|
|
2020-04-08 19:44:07 -04:00
|
|
|
// generate javadocs by calling javadoc tool
|
|
|
|
// see https://docs.oracle.com/en/java/javase/11/tools/javadoc.html
|
|
|
|
|
2020-03-11 11:09:26 -04:00
|
|
|
allprojects {
|
|
|
|
plugins.withType(JavaPlugin) {
|
2020-05-14 07:16:16 -04:00
|
|
|
ext {
|
|
|
|
relativeDocPath = project.path.replaceFirst(/:\w+:/, "").replace(':', '/')
|
|
|
|
}
|
2020-04-12 06:55:56 -04:00
|
|
|
|
|
|
|
// We disable the default javadoc task and have our own
|
|
|
|
// javadoc rendering task below. The default javadoc task
|
|
|
|
// will just invoke 'renderJavadoc' (to allow people to call
|
|
|
|
// conventional task name).
|
|
|
|
tasks.matching { it.name == "javadoc" }.all {
|
|
|
|
enabled = false
|
|
|
|
dependsOn "renderJavadoc"
|
|
|
|
}
|
|
|
|
|
2020-05-14 07:16:16 -04:00
|
|
|
task renderJavadoc(type: RenderJavadocTask) {
|
2020-04-08 19:44:07 -04:00
|
|
|
description "Generates Javadoc API documentation for the main source code. This directly invokes javadoc tool."
|
2020-03-11 11:09:26 -04:00
|
|
|
group "documentation"
|
|
|
|
|
|
|
|
dependsOn sourceSets.main.compileClasspath
|
2020-05-14 07:16:16 -04:00
|
|
|
classpath = sourceSets.main.compileClasspath;
|
|
|
|
srcDirSet = sourceSets.main.java;
|
2020-03-11 11:09:26 -04:00
|
|
|
|
2020-05-14 07:16:16 -04:00
|
|
|
outputDir = project.javadoc.destinationDir;
|
2020-03-11 11:09:26 -04:00
|
|
|
}
|
|
|
|
|
2020-05-14 07:16:16 -04:00
|
|
|
task renderSiteJavadoc(type: RenderJavadocTask) {
|
|
|
|
description "Generates Javadoc API documentation for the site (relative links)."
|
|
|
|
group "documentation"
|
2020-03-11 11:09:26 -04:00
|
|
|
|
2020-05-14 07:16:16 -04:00
|
|
|
dependsOn sourceSets.main.compileClasspath
|
|
|
|
classpath = sourceSets.main.compileClasspath;
|
|
|
|
srcDirSet = sourceSets.main.java;
|
2020-03-11 11:09:26 -04:00
|
|
|
|
2020-05-14 07:16:16 -04:00
|
|
|
relativeProjectLinks = true
|
2020-03-11 11:09:26 -04:00
|
|
|
|
2020-05-14 07:16:16 -04:00
|
|
|
// Place the documentation under Lucene or Solr's documentation directory.
|
|
|
|
// docroot is defined in 'documentation.gradle'
|
|
|
|
outputDir = project.docroot.toPath().resolve(project.relativeDocPath).toFile()
|
2020-03-11 11:09:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-14 07:16:16 -04:00
|
|
|
// Set up titles and link up some offline docs for all documentation
|
|
|
|
// (they may be unused but this doesn't do any harm).
|
|
|
|
def javaJavadocPackages = project.project(':lucene').file('tools/javadoc/java11/')
|
|
|
|
def junitJavadocPackages = project.project(':lucene').file('tools/javadoc/junit/')
|
|
|
|
allprojects {
|
|
|
|
project.tasks.withType(RenderJavadocTask) {
|
|
|
|
title = "${project.path.startsWith(':lucene') ? 'Lucene' : 'Solr'} ${project.version} ${project.name} API"
|
|
|
|
|
|
|
|
offlineLinks += [
|
|
|
|
"https://docs.oracle.com/en/java/javase/11/docs/api/": javaJavadocPackages,
|
|
|
|
"https://junit.org/junit4/javadoc/4.12/": junitJavadocPackages
|
|
|
|
]
|
2020-03-11 11:09:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-14 07:16:16 -04:00
|
|
|
// Fix for Java 11 Javadoc tool that cannot handle split packages between modules correctly.
|
|
|
|
// (by removing all the packages which are part of lucene-core)
|
|
|
|
// See: https://issues.apache.org/jira/browse/LUCENE-8738?focusedCommentId=16818106&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-16818106
|
|
|
|
configure(subprojects.findAll { it.path.startsWith(':lucene') && it.path != ':lucene:core' }) {
|
|
|
|
project.tasks.withType(RenderJavadocTask) {
|
|
|
|
doLast {
|
|
|
|
Set luceneCorePackages = file("${project(':lucene:core').tasks[name].outputDir}/element-list").readLines('UTF-8').toSet();
|
|
|
|
File elementFile = file("${outputDir}/element-list");
|
|
|
|
List elements = elementFile.readLines('UTF-8');
|
|
|
|
elements.removeAll(luceneCorePackages)
|
|
|
|
elementFile.write(elements.join('\n').concat('\n'), 'UTF-8');
|
2020-03-11 11:09:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
configure(project(':lucene:demo')) {
|
2020-05-14 07:16:16 -04:00
|
|
|
project.tasks.withType(RenderJavadocTask) {
|
|
|
|
// For the demo, we link the example source in the javadocs, as it's ref'ed elsewhere
|
|
|
|
linksource = true
|
2020-03-11 11:09:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-14 07:16:16 -04:00
|
|
|
// Disable Javadoc rendering for these projects.
|
|
|
|
configure(subprojects.findAll { it.path in [
|
|
|
|
':solr:solr-ref-guide',
|
|
|
|
':solr:server',
|
|
|
|
':solr:webapp']}) {
|
|
|
|
project.tasks.withType(RenderJavadocTask) {
|
|
|
|
enabled = false
|
2020-03-11 11:09:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-14 07:16:16 -04:00
|
|
|
// Add cross-project documentation task dependencies:
|
|
|
|
// - each RenderJavaDocs task gets a dependency to all tasks with same name in its dependencies
|
|
|
|
// - the dependency is using dependsOn with a closure to enable lazy evaluation
|
|
|
|
configure(subprojects) {
|
|
|
|
project.tasks.withType(RenderJavadocTask) { task ->
|
|
|
|
task.dependsOn {
|
|
|
|
task.project.configurations.implementation.allDependencies.withType(ProjectDependency).collect { dep ->
|
|
|
|
def otherProject = dep.dependencyProject
|
|
|
|
return otherProject.tasks.findByName(task.name)
|
2020-04-08 19:44:07 -04:00
|
|
|
}
|
2020-03-11 11:09:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-14 07:16:16 -04:00
|
|
|
class RenderJavadocTask extends DefaultTask {
|
|
|
|
@InputFiles
|
|
|
|
@SkipWhenEmpty
|
|
|
|
SourceDirectorySet srcDirSet;
|
|
|
|
|
|
|
|
@OutputDirectory
|
|
|
|
File outputDir
|
|
|
|
|
2020-05-15 18:14:05 -04:00
|
|
|
@CompileClasspath
|
2020-05-14 07:16:16 -04:00
|
|
|
FileCollection classpath
|
|
|
|
|
|
|
|
@Input
|
|
|
|
String title
|
|
|
|
|
|
|
|
@Input
|
|
|
|
boolean linksource = false
|
|
|
|
|
|
|
|
@Input
|
|
|
|
boolean relativeProjectLinks = false
|
|
|
|
|
|
|
|
@Input
|
|
|
|
def offlineLinks = [:]
|
|
|
|
|
|
|
|
@Input
|
2020-05-18 03:03:25 -04:00
|
|
|
def luceneDocUrl = "${->project.luceneDocUrl}"
|
2020-05-14 07:16:16 -04:00
|
|
|
|
|
|
|
@Input
|
2020-05-18 03:03:25 -04:00
|
|
|
def solrDocUrl = "${->project.solrDocUrl}"
|
2020-07-21 03:19:38 -04:00
|
|
|
|
|
|
|
@Nullable
|
|
|
|
@Optional
|
|
|
|
@Input
|
|
|
|
def executable
|
2020-05-14 07:16:16 -04:00
|
|
|
|
|
|
|
/** Utility method to recursively collect all tasks with same name like this one that we depend on */
|
|
|
|
private Set findRenderTasksInDependencies() {
|
|
|
|
Set found = []
|
|
|
|
def collectDeps
|
|
|
|
collectDeps = { task -> task.taskDependencies.getDependencies(task).findAll{ it.name == this.name && it.enabled && !found.contains(it) }.each{
|
|
|
|
found << it
|
|
|
|
collectDeps(it)
|
|
|
|
}}
|
|
|
|
collectDeps(this)
|
|
|
|
return found
|
2020-03-11 11:09:26 -04:00
|
|
|
}
|
|
|
|
|
2020-05-14 07:16:16 -04:00
|
|
|
@TaskAction
|
|
|
|
public void render() {
|
|
|
|
def srcDirs = srcDirSet.srcDirs.findAll { dir -> dir.exists() }
|
|
|
|
def optionsFile = project.file("${getTemporaryDir()}/javadoc-options.txt")
|
|
|
|
|
|
|
|
// create the directory, so relative link calculation knows that it's a directory:
|
|
|
|
outputDir.mkdirs();
|
|
|
|
|
|
|
|
def opts = []
|
|
|
|
opts << [ '-overview', project.file("${srcDirs[0]}/overview.html") ]
|
|
|
|
opts << [ '-sourcepath', srcDirs.join(File.pathSeparator) ]
|
|
|
|
opts << [ '-subpackages', project.path.startsWith(':lucene') ? 'org.apache.lucene' : 'org.apache.solr' ]
|
|
|
|
opts << [ '-d', outputDir ]
|
|
|
|
opts << '-protected'
|
|
|
|
opts << [ '-encoding', 'UTF-8' ]
|
|
|
|
opts << [ '-charset', 'UTF-8' ]
|
|
|
|
opts << [ '-docencoding', 'UTF-8' ]
|
|
|
|
opts << '-noindex'
|
|
|
|
opts << '-author'
|
|
|
|
opts << '-version'
|
|
|
|
if (linksource) {
|
|
|
|
opts << '-linksource'
|
2020-03-11 11:09:26 -04:00
|
|
|
}
|
2020-05-14 07:16:16 -04:00
|
|
|
opts << '-use'
|
|
|
|
opts << [ '-locale', 'en_US' ]
|
|
|
|
opts << [ '-windowtitle', title ]
|
|
|
|
opts << [ '-doctitle', title ]
|
|
|
|
if (!classpath.isEmpty()) {
|
|
|
|
opts << [ '-classpath', classpath.asPath ]
|
2020-03-11 11:09:26 -04:00
|
|
|
}
|
2020-05-14 07:16:16 -04:00
|
|
|
opts << [ '-bottom', "<i>Copyright © 2000-${project.buildYear} Apache Software Foundation. All Rights Reserved.</i>" ]
|
|
|
|
|
|
|
|
opts << [ '-tag', 'lucene.experimental:a:WARNING: This API is experimental and might change in incompatible ways in the next release.' ]
|
|
|
|
opts << [ '-tag', 'lucene.internal:a:NOTE: This API is for internal purposes only and might change in incompatible ways in the next release.' ]
|
|
|
|
opts << [ '-tag', "lucene.spi:t:SPI Name (case-insensitive: if the name is 'htmlStrip', 'htmlstrip' can be used when looking up the service)." ]
|
|
|
|
|
|
|
|
def allOfflineLinks = [:]
|
|
|
|
allOfflineLinks.putAll(offlineLinks)
|
|
|
|
|
|
|
|
// Resolve inter-project links:
|
|
|
|
// - find all (enabled) tasks this tasks depends on (with same name), calling findRenderTasksInDependencies()
|
|
|
|
// - sort the tasks preferring those whose project name equals 'core', then lexigraphical by path
|
|
|
|
// - for each task get output dir to create relative or absolute link
|
2020-07-27 19:04:21 -04:00
|
|
|
// NOTE: explicitly exclude solr/test-framework, or attempting to link to lucene-test-framework because if we did javadoc would
|
|
|
|
// attempt to link class refs in in org.apache.lucene, causing broken links. (either broken links to things like "Directory" if
|
|
|
|
// lucene-test-framework was first, or broken links to things like LuceneTestCase if lucene-core was first)
|
|
|
|
if (project.path != ':solr:test-framework') { //
|
|
|
|
findRenderTasksInDependencies()
|
|
|
|
.sort(false, Comparator.comparing { (it.project.name != 'core') as Boolean }.thenComparing(Comparator.comparing { it.path }))
|
|
|
|
.each { otherTask ->
|
|
|
|
def otherProject = otherTask.project
|
|
|
|
// For relative links we compute the actual relative link between projects.
|
|
|
|
def crossLuceneSolr = (otherProject.docroot != project.docroot)
|
|
|
|
if (relativeProjectLinks && !crossLuceneSolr) {
|
|
|
|
def pathTo = otherTask.outputDir.toPath().toAbsolutePath()
|
|
|
|
def pathFrom = outputDir.toPath().toAbsolutePath()
|
|
|
|
def relative = pathFrom.relativize(pathTo).toString().replace(File.separator, '/')
|
|
|
|
opts << ['-link', relative]
|
|
|
|
} else {
|
|
|
|
// For absolute links, we determine the target URL by assembling the full URL.
|
|
|
|
def base = otherProject.path.startsWith(":lucene") ? luceneDocUrl : solrDocUrl
|
|
|
|
allOfflineLinks.put("${base}/${otherProject.relativeDocPath}/".toString(), otherTask.outputDir)
|
|
|
|
}
|
2020-05-14 07:16:16 -04:00
|
|
|
}
|
2020-07-27 19:04:21 -04:00
|
|
|
}
|
2020-05-14 07:16:16 -04:00
|
|
|
|
|
|
|
// Add offline links.
|
|
|
|
allOfflineLinks.each { url, dir ->
|
|
|
|
// Some sanity check/ validation here to ensure dir/package-list or dir/element-list is present.
|
|
|
|
if (!project.file("$dir/package-list").exists() &&
|
|
|
|
!project.file("$dir/element-list").exists()) {
|
|
|
|
throw new GradleException("Expected pre-rendered package-list or element-list at ${dir}.")
|
2020-04-08 19:44:07 -04:00
|
|
|
}
|
2020-05-14 07:16:16 -04:00
|
|
|
opts << [ '-linkoffline', url, dir ]
|
2020-03-11 11:09:26 -04:00
|
|
|
}
|
|
|
|
|
2020-05-14 07:16:16 -04:00
|
|
|
opts << [ '--release', 11 ]
|
|
|
|
opts << '-Xdoclint:all,-missing'
|
2020-04-08 19:44:07 -04:00
|
|
|
|
2020-05-14 07:16:16 -04:00
|
|
|
// Temporary file that holds all javadoc options for the current task.
|
|
|
|
optionsFile.withWriter("UTF-8", { writer ->
|
|
|
|
// escapes an option with single quotes or whitespace to be passed in the options.txt file for
|
|
|
|
def escapeJavadocOption = { String s -> (s =~ /[ '"]/) ? ("'" + s.replaceAll(/[\\'"]/, /\\$0/) + "'") : s }
|
2020-03-11 11:09:26 -04:00
|
|
|
|
2020-05-14 07:16:16 -04:00
|
|
|
opts.each { entry ->
|
|
|
|
if (entry instanceof List) {
|
|
|
|
writer.write(entry.collect { escapeJavadocOption(it as String) }.join(" "))
|
|
|
|
} else {
|
|
|
|
writer.write(escapeJavadocOption(entry as String))
|
2020-04-08 19:44:07 -04:00
|
|
|
}
|
2020-05-14 07:16:16 -04:00
|
|
|
writer.write('\n')
|
2020-03-11 11:09:26 -04:00
|
|
|
}
|
2020-05-14 07:16:16 -04:00
|
|
|
})
|
2020-03-11 11:09:26 -04:00
|
|
|
|
2020-07-21 03:19:38 -04:00
|
|
|
def javadocCmd = {
|
|
|
|
if (executable == null) {
|
|
|
|
JavaInstallationRegistry registry = project.extensions.getByType(JavaInstallationRegistry)
|
|
|
|
JavaInstallation currentJvm = registry.installationForCurrentVirtualMachine.get()
|
|
|
|
return currentJvm.jdk.get().javadocExecutable.asFile
|
|
|
|
} else {
|
|
|
|
return project.file(executable)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
logger.info("Javadoc executable used: ${javadocCmd}")
|
|
|
|
|
2020-05-14 07:16:16 -04:00
|
|
|
def outputFile = project.file("${getTemporaryDir()}/javadoc-output.txt")
|
|
|
|
def result
|
|
|
|
outputFile.withOutputStream { output ->
|
|
|
|
result = project.exec {
|
|
|
|
executable javadocCmd
|
2020-03-11 11:09:26 -04:00
|
|
|
|
2020-05-14 07:16:16 -04:00
|
|
|
standardOutput = output
|
|
|
|
errorOutput = output
|
|
|
|
|
|
|
|
args += [ "@${optionsFile}" ]
|
|
|
|
|
|
|
|
// -J flags can't be passed via options file... (an error "javadoc: error - invalid flag: -J-Xmx512m" occurs.)
|
|
|
|
args += [ "-J-Xmx512m" ]
|
|
|
|
// force locale to be "en_US" (fix for: https://bugs.openjdk.java.net/browse/JDK-8222793)
|
|
|
|
args += [ "-J-Duser.language=en", "-J-Duser.country=US" ]
|
|
|
|
|
|
|
|
ignoreExitValue true
|
2020-04-08 19:44:07 -04:00
|
|
|
}
|
2020-03-11 11:09:26 -04:00
|
|
|
}
|
|
|
|
|
2020-05-14 07:16:16 -04:00
|
|
|
if (result.getExitValue() != 0) {
|
|
|
|
// Pipe the output to console. Intentionally skips any encoding conversion
|
|
|
|
// and pumps raw bytes.
|
|
|
|
System.out.write(outputFile.bytes)
|
|
|
|
|
|
|
|
def cause
|
|
|
|
try {
|
|
|
|
result.rethrowFailure()
|
|
|
|
} catch (ex) {
|
|
|
|
cause = ex
|
2020-04-08 19:44:07 -04:00
|
|
|
}
|
2020-05-14 07:16:16 -04:00
|
|
|
throw new GradleException("Javadoc generation failed for ${project.path},\n Options file at: ${optionsFile}\n Command output at: ${outputFile}", cause)
|
2020-03-11 11:09:26 -04:00
|
|
|
}
|
|
|
|
|
2020-05-14 07:16:16 -04:00
|
|
|
// append some special table css, prettify css
|
|
|
|
ant.concat(destfile: "${outputDir}/stylesheet.css", append: "true", fixlastline: "true", encoding: "UTF-8") {
|
|
|
|
filelist(dir: project.project(":lucene").file("tools/javadoc"), files: "table_padding.css")
|
|
|
|
filelist(dir: project.project(":lucene").file("tools/prettify"), files: "prettify.css")
|
2020-03-11 11:09:26 -04:00
|
|
|
}
|
2020-05-14 07:16:16 -04:00
|
|
|
// append prettify to scripts
|
|
|
|
ant.concat(destfile: "${outputDir}/script.js", append: "true", fixlastline: "true", encoding: "UTF-8") {
|
|
|
|
filelist(dir: project.project(':lucene').file("tools/prettify"), files: "prettify.js inject-javadocs.js")
|
|
|
|
}
|
|
|
|
ant.fixcrlf(srcdir: outputDir, includes: "stylesheet.css script.js", eol: "lf", fixlast: "true", encoding: "UTF-8")
|
2020-03-11 11:09:26 -04:00
|
|
|
}
|
|
|
|
}
|