HHH-17047 - Follow up tasks for Gradle 8.2 upgrade

- toolchains
- lazy Task creation
- documentation (documentation/ and release/) tasks
This commit is contained in:
Steve Ebersole 2023-08-10 09:20:24 -05:00 committed by Christian Beikov
parent 762a35b90f
commit e77364b808
22 changed files with 843 additions and 738 deletions

View File

@ -1,3 +1,5 @@
import java.util.function.Function
import org.asciidoctor.gradle.jvm.AsciidoctorTask import org.asciidoctor.gradle.jvm.AsciidoctorTask
import org.asciidoctor.gradle.jvm.pdf.AsciidoctorPdfTask import org.asciidoctor.gradle.jvm.pdf.AsciidoctorPdfTask
@ -5,6 +7,7 @@ plugins {
id 'org.asciidoctor.jvm.convert' version '3.3.2' id 'org.asciidoctor.jvm.convert' version '3.3.2'
id 'org.asciidoctor.jvm.pdf' version '3.3.2' id 'org.asciidoctor.jvm.pdf' version '3.3.2'
id "org.asciidoctor.jvm.gems" version "3.3.2" id "org.asciidoctor.jvm.gems" version "3.3.2"
id "org.hibernate.orm.build.settings-doc"
} }
repositories { repositories {
@ -28,8 +31,88 @@ apply plugin: 'org.hibernate.orm.build.reports'
defaultTasks 'buildDocs' defaultTasks 'buildDocs'
configurations {
core
testing
envers
spatial
agroal
c3p0
hikaricp
proxool
vibur
jcache
jpamodelgen
javadocClasspath {
description = 'Class files for the javadoc to be built'
resolutionStrategy.capabilitiesResolution.withCapability('org.junit.jupiter:junit-jupiter-params:5.7.1') { details ->
details.select( details.candidates.first() ).because( 'first' )
}
extendsFrom core
extendsFrom testing
extendsFrom envers
extendsFrom spatial
extendsFrom agroal
extendsFrom c3p0
extendsFrom hikaricp
extendsFrom proxool
extendsFrom vibur
extendsFrom jcache
extendsFrom jpamodelgen
}
javadocSources {
description = 'Source files to be built by the javadoc tool'
}
}
dependencies { dependencies {
attributesSchema { schema ->
schema.attribute(Bundling.BUNDLING_ATTRIBUTE) { matchStrategy ->
final def nameComparator = Comparator.comparing(
new Function<Bundling,String>() {
@Override
String apply(Bundling o) {
return o.name
}
}
)
matchStrategy.ordered(new Comparator<Bundling>() {
@Override
int compare(Bundling o1, Bundling o2) {
if ( Objects.equals( o1, o2 ) ) {
return 0;
}
if ( o1 == null ) {
return 1;
}
if ( o2 == null ) {
return -1;
}
if ( o1.name == Bundling.EMBEDDED ) {
return -1;
}
if ( o2.name == Bundling.EMBEDDED ) {
return 1;
}
return nameComparator.compare(o1,o2)
}
} )
}
}
ext.pressgangVersion = '3.0.0' ext.pressgangVersion = '3.0.0'
reportAggregation project( ':hibernate-agroal' ) reportAggregation project( ':hibernate-agroal' )
@ -48,6 +131,51 @@ dependencies {
reportAggregation project(':hibernate-jpamodelgen') reportAggregation project(':hibernate-jpamodelgen')
asciidoctorGems 'rubygems:rouge:4.1.1' asciidoctorGems 'rubygems:rouge:4.1.1'
core project( ':hibernate-core' )
javadocSources project( path: ':hibernate-core', configuration: 'javadocSources' )
testing project( ':hibernate-testing' )
javadocSources project( path: ':hibernate-testing', configuration: 'javadocSources' )
envers project( ':hibernate-envers' )
javadocSources project( path: ':hibernate-envers', configuration: 'javadocSources' )
spatial project( ':hibernate-spatial' )
javadocSources project( path: ':hibernate-spatial', configuration: 'javadocSources' )
agroal project( ':hibernate-agroal' )
javadocSources project( path: ':hibernate-agroal', configuration: 'javadocSources' )
c3p0 project( ':hibernate-c3p0' )
javadocSources project( path: ':hibernate-c3p0', configuration: 'javadocSources' )
hikaricp project( ':hibernate-hikaricp' )
javadocSources project( path: ':hibernate-hikaricp', configuration: 'javadocSources' )
proxool project( ':hibernate-proxool' )
javadocSources project( path: ':hibernate-proxool', configuration: 'javadocSources' )
vibur project( ':hibernate-vibur' )
javadocSources project( path: ':hibernate-vibur', configuration: 'javadocSources' )
jcache project( ':hibernate-jcache' )
javadocSources project( path: ':hibernate-jcache', configuration: 'javadocSources' )
jpamodelgen project( ':hibernate-jpamodelgen' )
javadocSources project( path: ':hibernate-jpamodelgen', configuration: 'javadocSources' )
javadocClasspath libs.loggingAnnotations
javadocClasspath jakartaLibs.validation
javadocClasspath jakartaLibs.cdi
javadocClasspath jakartaLibs.jacc
javadocClasspath jakartaLibs.jsonbApi
javadocClasspath libs.ant
javadocClasspath dbLibs.postgresql
javadocClasspath libs.jackson
javadocClasspath gradleApi()
javadocClasspath libs.jacksonXml
javadocClasspath dbLibs.oracle
} }
@ -60,6 +188,68 @@ else {
tasks.release.dependsOn clean tasks.release.dependsOn clean
} }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// aggregated JavaDoc
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def aggregateJavadocsTask = tasks.register( "aggregateJavadocs", Javadoc ) {
group = "documentation"
description = 'Builds an aggregated JavaDoc across all ORM sub-projects'
inputs.property "ormVersion", project.ormVersion
destinationDir = mkdir( layout.buildDirectory.file( 'javadocs' ) )
source configurations.javadocSources
classpath += configurations.javadocClasspath
// exclude any generated sources and internal packages
exclude '**/generated-src/**'
exclude '**/internal/**'
include '**/*.java'
final int currentYear = new GregorianCalendar().get( Calendar.YEAR )
// apply standard config
maxMemory = '512m'
configure( options ) {
overview = 'src/javadoc/overview.html'
stylesheetFile = new File( projectDir, 'src/javadoc/stylesheet.css' )
windowTitle = 'Hibernate JavaDocs'
docTitle = "Hibernate JavaDoc ($project.version)"
bottom = "Copyright &copy; 2001-$currentYear <a href=\"https://redhat.com\">Red Hat, Inc.</a> All Rights Reserved."
use = true
options.encoding = 'UTF-8'
links = [
'https://docs.oracle.com/en/java/javase/11/docs/api/',
'https://docs.jboss.org/hibernate/beanvalidation/spec/2.0/api/',
'https://docs.jboss.org/cdi/api/2.0/',
'https://jakarta.ee/specifications/platform/8/apidocs/'
]
options.addStringOption( 'Xdoclint:none', '-quiet' )
if ( jdkVersions.explicit ) {
options.setJFlags(
getProperty( 'toolchain.javadoc.jvmargs' ).toString().
split( ' ' ).toList().findAll( { !it.isEmpty() } )
)
}
}
if ( jdkVersions.explicit ) {
// Display version of Java tools
doFirst {
if ( javadocTool.present ) {
logger.lifecycle "Aggregating javadoc with '${javadocTool.get().metadata.installationPath}'"
}
}
}
}
asciidoctorj { asciidoctorj {
requires 'rouge' requires 'rouge'
modules { modules {
@ -394,14 +584,31 @@ tasks.register('renderQL', AsciidoctorTask) {task->
// User Guide ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // User Guide ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def generateSettingsDocTask = tasks.named( "generateSettingsDoc" ) {
// dependsOn aggregateJavadocsTask
javadocDirectory = aggregateJavadocsTask.get().destinationDir
sections {
core {
settingsClassName = "org.hibernate.cfg.AvailableSettings"
projectPath = ":hibernate-core"
}
envers {
settingsClassName = "org.hibernate.envers.configuration.EnversSettings"
projectPath = ":hibernate-envers"
}
jcache {
settingsClassName = "org.hibernate.cache.jcache.ConfigSettings"
projectPath = ":hibernate-jcache"
}
}
}
def renderUserGuideHtmlTask = tasks.register( 'renderUserGuideHtml', AsciidoctorTask ) { task -> def renderUserGuideHtmlTask = tasks.register( 'renderUserGuideHtml', AsciidoctorTask ) { task ->
group = "Documentation" group = "Documentation"
description = 'Renders the User Guides in HTML format using Asciidoctor.' description = 'Renders the User Guides in HTML format using Asciidoctor.'
inputs.property "hibernate-version", project.ormVersion inputs.property "hibernate-version", project.ormVersion
dependsOn ':hibernate-core:collectConfigProperties' dependsOn generateSettingsDocTask
dependsOn ':hibernate-envers:collectConfigProperties'
dependsOn ':hibernate-jcache:collectConfigProperties'
sourceDir = file( 'src/main/asciidoc/userguide' ) sourceDir = file( 'src/main/asciidoc/userguide' )
sources { sources {
@ -568,6 +775,7 @@ def generateReportsTask = tasks.named( "generateReports" ) {
def buildDocsTask = tasks.register( 'buildDocs' ) { task -> def buildDocsTask = tasks.register( 'buildDocs' ) { task ->
task.group = 'Documentation' task.group = 'Documentation'
task.description = 'Grouping task for performing all documentation building tasks' task.description = 'Grouping task for performing all documentation building tasks'
task.dependsOn aggregateJavadocsTask
task.dependsOn renderGettingStartedGuidesTask task.dependsOn renderGettingStartedGuidesTask
task.dependsOn renderIntroductionGuidesTask task.dependsOn renderIntroductionGuidesTask
task.dependsOn renderUserGuidesTask task.dependsOn renderUserGuidesTask

View File

@ -1,5 +1,3 @@
== List of all available configuration properties == List of all available configuration properties
include::../../../../target/config-properties/hibernate-core.asciidoc[opts=optional] include::{documentation-project-dir}/target/asciidoc/fragments/config-settings.adoc
include::../../../../target/config-properties/hibernate-envers.asciidoc[opts=optional]
include::../../../../target/config-properties/hibernate-jcache.asciidoc[opts=optional]

View File

@ -3,7 +3,8 @@ Vlad Mihalcea, Steve Ebersole, Andrea Boriero, Gunnar Morling, Gail Badner, Chri
:toc2: :toc2:
:toclevels: 3 :toclevels: 3
:sectanchors: :sectanchors:
:root-project-dir: ../../../../../../.. :documentation-project-dir: ../../../..
:root-project-dir: {documentation-project-dir}/..
include::Preface.adoc[] include::Preface.adoc[]

View File

@ -19,7 +19,6 @@ description = 'Hibernate\'s core ORM functionality'
apply from: rootProject.file( 'gradle/published-java-module.gradle' ) apply from: rootProject.file( 'gradle/published-java-module.gradle' )
apply plugin: 'org.hibernate.orm.antlr' apply plugin: 'org.hibernate.orm.antlr'
apply plugin: 'org.hibernate.matrix-test' apply plugin: 'org.hibernate.matrix-test'
apply plugin: 'org.hibernate.orm.build.properties'
configurations { configurations {
tests { tests {
@ -321,14 +320,6 @@ javadoc {
} }
} }
task collectConfigProperties { task ->
description 'Collect config properties'
tasks.generateConfigsProperties.javadocsBaseLink = 'https://docs.jboss.org/hibernate/orm/' + rootProject.ormVersion.family + '/javadocs/'
dependsOn tasks.generateConfigsProperties
}
tasks.sourcesJar.dependsOn ':hibernate-core:generateGraphParser' tasks.sourcesJar.dependsOn ':hibernate-core:generateGraphParser'
tasks.sourcesJar.dependsOn ':hibernate-core:generateHqlParser' tasks.sourcesJar.dependsOn ':hibernate-core:generateHqlParser'
tasks.sourcesJar.dependsOn ':hibernate-core:generateSqlScriptParser' tasks.sourcesJar.dependsOn ':hibernate-core:generateSqlScriptParser'

View File

@ -9,7 +9,6 @@ description = 'Hibernate\'s entity version (audit/history) support'
apply from: rootProject.file( 'gradle/published-java-module.gradle' ) apply from: rootProject.file( 'gradle/published-java-module.gradle' )
apply plugin: 'org.hibernate.matrix-test' apply plugin: 'org.hibernate.matrix-test'
apply plugin: 'org.hibernate.orm.build.properties'
dependencies { dependencies {
api project( ':hibernate-core' ) api project( ':hibernate-core' )
@ -70,11 +69,3 @@ tasks."matrix_mariadb" {
println "Starting test: " + descriptor println "Starting test: " + descriptor
} }
} }
task collectConfigProperties { task ->
description 'Collect config properties'
tasks.generateConfigsProperties.javadocsBaseLink = 'https://docs.jboss.org/hibernate/orm/' + rootProject.ormVersion.family + '/javadocs/'
dependsOn tasks.generateConfigsProperties
}

View File

@ -1,7 +1,6 @@
description = 'Integration for javax.cache into Hibernate as a second-level caching service' description = 'Integration for javax.cache into Hibernate as a second-level caching service'
apply from: rootProject.file( 'gradle/published-java-module.gradle' ) apply from: rootProject.file( 'gradle/published-java-module.gradle' )
apply plugin: 'org.hibernate.orm.build.properties'
dependencies { dependencies {
api project( ':hibernate-core' ) api project( ':hibernate-core' )
@ -15,11 +14,3 @@ dependencies {
} }
} }
} }
task collectConfigProperties { task ->
description 'Collect config properties'
tasks.generateConfigsProperties.javadocsBaseLink = 'https://docs.jboss.org/hibernate/orm/' + rootProject.ormVersion.family + '/javadocs/'
dependsOn tasks.generateConfigsProperties
}

View File

@ -64,9 +64,9 @@ gradlePlugin {
id = 'org.hibernate.orm.build.env-project' id = 'org.hibernate.orm.build.env-project'
implementationClass = 'org.hibernate.orm.env.EnvironmentProjectPlugin' implementationClass = 'org.hibernate.orm.env.EnvironmentProjectPlugin'
} }
configPropertiesCollectorPlugin { settingsDocumentationPlugin {
id = 'org.hibernate.orm.build.properties' id = 'org.hibernate.orm.build.settings-doc'
implementationClass = 'org.hibernate.orm.properties.ConfigPropertyCollectorPlugin' implementationClass = 'org.hibernate.orm.properties.SettingsDocumentationPlugin'
} }
jdkVersionsPlugin { jdkVersionsPlugin {
id = 'org.hibernate.orm.build.jdks' id = 'org.hibernate.orm.build.jdks'

View File

@ -7,52 +7,78 @@
package org.hibernate.orm.properties; package org.hibernate.orm.properties;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import java.util.Set; import java.nio.file.Files;
import java.util.function.BiConsumer; import java.util.Map;
import java.util.SortedMap;
import java.util.SortedSet;
public class AsciiDocWriter implements BiConsumer<Set<ConfigurationProperty>, Writer> { import org.gradle.api.Project;
import org.gradle.api.file.RegularFile;
private final String anchor; public class AsciiDocWriter {
private final String title; public static final String ANCHOR_BASE = "settings-";
public static final String ANCHOR_START = "[[" + ANCHOR_BASE;
public AsciiDocWriter(String anchor, String title) { public static void writeToFile(
this.anchor = anchor; SortedMap<SettingsDocSection, SortedSet<SettingDescriptor>> settingDescriptorMap,
this.title = title; RegularFile outputFile,
Project project) {
final File outputFileAsFile = outputFile.getAsFile();
try {
Files.createDirectories( outputFileAsFile.getParentFile().toPath() );
}
catch (IOException e) {
throw new RuntimeException( "Unable to prepare output directory for writing", e );
} }
@Override try ( FileWriter fileWriter = new FileWriter( outputFileAsFile ) ) {
public void accept(Set<ConfigurationProperty> properties, Writer writer) { write( settingDescriptorMap, fileWriter, project );
try { }
tryToWriteLine( writer, "[[configuration-properties-aggregated-", anchor, "]]" ); catch (IOException e) {
tryToWriteLine( writer, "=== ", title ); throw new RuntimeException( "Failed to produce asciidoc output for collected properties", e );
}
}
private static void write(
SortedMap<SettingsDocSection, SortedSet<SettingDescriptor>> settingDescriptorMap,
FileWriter writer,
Project project) throws IOException {
for ( Map.Entry<SettingsDocSection, SortedSet<SettingDescriptor>> entry : settingDescriptorMap.entrySet() ) {
final SettingsDocSection sectionDescriptor = entry.getKey();
final SortedSet<SettingDescriptor> sectionSettingDescriptors = entry.getValue();
final Project sourceProject = project.getRootProject().project( sectionDescriptor.getProjectPath() );
// write an anchor in the form `[[settings-{moduleName}]]`, e.g. `[[settings-hibernate-core]]`
tryToWriteLine( writer, ANCHOR_START, sourceProject.getName(), "]]" );
tryToWriteLine( writer, "=== ", sourceProject.getDescription() );
writer.write( '\n' ); writer.write( '\n' );
for ( ConfigurationProperty el : properties ) {
String key = el.key(); for ( SettingDescriptor settingDescriptor : sectionSettingDescriptors ) {
writer.write( "[[" ); writer.write( ANCHOR_START );
writer.write( "configuration-properties-aggregated-" ); writer.write( settingDescriptor.getName() );
writer.write( el.anchorPrefix() );
writer.write( key.replaceAll( "[^\\w-.]", "-" ) );
writer.write( "]] " ); writer.write( "]] " );
writer.write( '`' ); writer.write( '`' );
writer.write( key ); writer.write( settingDescriptor.getName() );
writer.write( '`' ); writer.write( '`' );
writer.write( "::\n" ); writer.write( "::\n" );
writer.write( el.javadoc() ); writer.write( settingDescriptor.getJavadoc() );
writer.write( '\n' ); writer.write( '\n' );
} }
writer.write( '\n' ); writer.write( '\n' );
} }
catch (IOException e) {
throw new RuntimeException( "Unable to create asciidoc output", e );
}
} }
private void tryToWriteLine(Writer writer, String prefix, String value, String... other) { private static void tryToWriteLine(Writer writer, String prefix, String value, String... other) {
try { try {
writer.write( prefix ); writer.write( prefix );
writer.write( value ); writer.write( value );

View File

@ -1,32 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.properties;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
public class ConfigPropertyCollectorPlugin implements Plugin<Project> {
public static final String TASK_GROUP_NAME = "hibernate-properties";
@Override
public void apply(Project project) {
final Task groupingTask = project.getTasks().maybeCreate( "generateHibernateConfigProperties" );
groupingTask.setGroup( TASK_GROUP_NAME );
Task javadoc = project.getTasks().maybeCreate( "javadoc" );
groupingTask.dependsOn( javadoc );
final ConfigPropertyCollectorTask configPropertyCollectorTask = project.getTasks().create(
"generateConfigsProperties",
ConfigPropertyCollectorTask.class
);
configPropertyCollectorTask.dependsOn( javadoc );
groupingTask.dependsOn( configPropertyCollectorTask );
}
}

View File

@ -1,68 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
*/
package org.hibernate.orm.properties;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
import javax.inject.Inject;
import org.gradle.api.DefaultTask;
import org.gradle.api.Project;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.TaskAction;
public class ConfigPropertyCollectorTask extends DefaultTask {
private final Path javadocsLocation;
private final Property<String> javadocsBaseLink;
private final String anchor;
private final String moduleName;
private final ConfigPropertyHolder propertyHolder = new ConfigPropertyHolder();
private final Path output;
private final String fileName;
@Inject
public ConfigPropertyCollectorTask(Project project) {
this.javadocsLocation = project.getBuildDir().toPath().resolve( "docs/javadoc" );
this.javadocsBaseLink = project.getObjects().property( String.class );
this.anchor = project.getName() + "-";
this.moduleName = project.getDescription();
this.output = project.getRootProject().project( ":documentation" ).getBuildDir().toPath()
.resolve( "config-properties" );
this.fileName = project.getName() + ".asciidoc";
}
@Internal
public Property<String> getJavadocsBaseLink() {
return javadocsBaseLink;
}
@TaskAction
public void generateConfigProperties() {
new ConfigurationPropertyCollector(
propertyHolder, getLogger(), javadocsLocation, javadocsBaseLink.get(), anchor, moduleName
).processClasses();
try{
Files.createDirectories( output );
}
catch (IOException e) {
throw new RuntimeException( "Unable to prepare output directory structure", e );
}
try ( Writer writer = new FileWriter( output.resolve( fileName ).toFile() ) ) {
propertyHolder.write( new AsciiDocWriter( anchor, moduleName ), writer );
}
catch (IOException e) {
throw new RuntimeException( "Failed to produce asciidoc output for collected properties", e );
}
}
}

View File

@ -1,39 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.properties;
import java.io.Writer;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
public class ConfigPropertyHolder {
private final Set<ConfigurationProperty> properties = new TreeSet<>();
public boolean isEmpty() {
return properties.isEmpty();
}
public void write(BiConsumer<Set<ConfigurationProperty>, Writer> transformer, Writer writer) {
transformer.accept( this.properties, writer );
}
public void add(ConfigurationProperty property) {
properties.add( property );
}
public boolean hasProperties() {
return !properties.isEmpty();
}
public boolean hasProperties(Predicate<ConfigurationProperty> filter) {
return properties.stream().anyMatch( filter );
}
}

View File

@ -1,103 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.properties;
import java.util.Comparator;
import java.util.Objects;
public class ConfigurationProperty implements Comparable<ConfigurationProperty> {
private static final Comparator<ConfigurationProperty> CONFIGURATION_PROPERTY_COMPARATOR = Comparator.comparing(
ConfigurationProperty::key );
private String key;
private String javadoc;
private String sourceClass;
private String anchorPrefix;
private String moduleName;
public String key() {
return key;
}
public ConfigurationProperty key(String key) {
this.key = key;
return this;
}
public String javadoc() {
return javadoc;
}
public ConfigurationProperty javadoc(String javadoc) {
this.javadoc = javadoc == null ? "" : javadoc;
return this;
}
public String sourceClass() {
return sourceClass;
}
public ConfigurationProperty sourceClass(String sourceClass) {
this.sourceClass = sourceClass;
return this;
}
public String anchorPrefix() {
return anchorPrefix;
}
public ConfigurationProperty anchorPrefix(String anchorPrefix) {
this.anchorPrefix = anchorPrefix.replaceAll( "[^\\w-.]", "_" );
return this;
}
public String moduleName() {
return moduleName;
}
public ConfigurationProperty moduleName(String moduleName) {
this.moduleName = moduleName;
return this;
}
@Override
public String toString() {
return "ConfigurationProperty{" +
"key='" + key + '\'' +
", javadoc='" + javadoc + '\'' +
", sourceClass='" + sourceClass + '\'' +
", anchorPrefix='" + anchorPrefix + '\'' +
", moduleName='" + moduleName + '\'' +
'}';
}
@Override
public int compareTo(ConfigurationProperty o) {
return CONFIGURATION_PROPERTY_COMPARATOR.compare( this, o );
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
ConfigurationProperty that = (ConfigurationProperty) o;
return Objects.equals( key, that.key ) &&
Objects.equals( javadoc, that.javadoc ) &&
Objects.equals( sourceClass, that.sourceClass ) &&
Objects.equals( anchorPrefix, that.anchorPrefix ) &&
Objects.equals( moduleName, that.moduleName );
}
@Override
public int hashCode() {
return Objects.hash( key, javadoc, sourceClass, anchorPrefix, moduleName );
}
}

View File

@ -1,247 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.properties;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
import org.gradle.api.logging.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.nodes.TextNode;
import org.jsoup.select.Elements;
public class ConfigurationPropertyCollector {
private final ConfigPropertyHolder propertyHolder;
private final Logger logger;
// configs:
private final Path javadocsLocation;
private final String javadocsBaseLink;
private final String anchor;
private final String moduleName;
public ConfigurationPropertyCollector(ConfigPropertyHolder propertyHolder, Logger logger, Path javadocsLocation,
String javadocsBaseLink, String anchor, String moduleName) {
this.propertyHolder = propertyHolder;
this.logger = logger;
this.javadocsLocation = javadocsLocation;
this.javadocsBaseLink = javadocsBaseLink;
this.anchor = anchor;
this.moduleName = moduleName;
}
public void processClasses() {
processClasses( locateConstants() );
}
private void processClasses(Document constants) {
for ( Element table : constants.select( "table.constantsSummary" ) ) {
String className = table.selectFirst( "caption" ).text();
if ( className.endsWith( "Settings" ) && !className.contains( ".impl." ) && !className.contains( ".internal." ) ) {
// assume that such class is a config class and we want to collect properties from it.
Optional<Document> javadoc = obtainJavadoc( className );
javadoc.ifPresent( doc -> {
// go through constants:
for ( Element row : table.select( "tr" ) ) {
if ( row.hasClass( "altColor" ) || row.hasClass( "rowColor" ) ) {
propertyHolder.add(
new ConfigurationProperty()
.key( stripQuotes( row.selectFirst( ".colLast" ).text() ) )
.javadoc(
extractJavadoc(
doc,
className,
withoutPackagePrefix( row.selectFirst( ".colFirst a" ).id() )
)
)
.sourceClass( className )
.anchorPrefix( anchor )
.moduleName( moduleName )
);
}
}
} );
}
}
}
private String stripQuotes(String value) {
if ( value.startsWith( "\"" ) && value.endsWith( "\"" ) ) {
return value.substring( 1, value.length() - 1 );
}
return value;
}
private String extractJavadoc(Document javadoc, String className, String constant) {
org.jsoup.nodes.Element block = javadoc.selectFirst( "#" + constant + " + ul li.blockList" );
if ( block != null ) {
for ( org.jsoup.nodes.Element link : block.getElementsByTag( "a" ) ) {
String href = link.attr( "href" );
// only update links if they are not external:
if ( !link.hasClass( "external-link" ) ) {
if ( href.startsWith( "#" ) ) {
href = withoutPackagePrefix( className ) + ".html" + href;
}
String packagePath = packagePrefix(className).replace( ".", File.separator );
href = javadocsBaseLink + packagePath + "/" + href;
}
else if ( href.contains( "/build/parents/" ) && href.contains( "/apidocs" ) ) {
// means a link was to a class from other module and javadoc plugin generated some external link
// that won't work. So we replace it:
href = javadocsBaseLink + href.substring( href.indexOf( "/apidocs" ) + "/apidocs".length() );
}
link.attr( "href", href );
}
Elements result = new Elements();
for ( org.jsoup.nodes.Element child : block.children() ) {
if ( "h4".equalsIgnoreCase( child.tagName() ) || "pre".equalsIgnoreCase( child.tagName() ) ) {
continue;
}
result.add( child );
}
return convertToAsciidoc( result );
}
return "";
}
private String convertToAsciidoc(Elements elements) {
StringBuilder doc = new StringBuilder( "" );
for ( Element element : elements ) {
convertToAsciidoc( element, doc, false );
}
return doc.toString();
}
private void convertToAsciidoc(Node node, StringBuilder doc, boolean innerBlock) {
if ( node instanceof Element ) {
Element element = (Element) node;
String tag = element.tagName();
if ( "p".equalsIgnoreCase( tag ) || "div".equalsIgnoreCase( tag ) || "dl".equalsIgnoreCase( tag ) ) {
if ( doc.length() != 0 ) {
if ( !innerBlock ) {
doc.append( "\n+" );
}
doc.append( "\n\n" );
}
boolean deprecation = element.hasClass( "deprecationBlock" );
if ( deprecation ) {
doc.append( "+\n[WARNING]\n====\n" );
}
for ( Node child : element.childNodes() ) {
convertToAsciidoc( child, doc, deprecation );
}
doc.append( '\n' );
if ( deprecation ) {
doc.append( "====\n" );
}
}
else if ( "a".equalsIgnoreCase( tag ) ) {
convertToAsciidoc( element, "link:" + element.attr( "href" ) + "[", "]", doc, innerBlock );
}
else if ( "code".equalsIgnoreCase( tag ) ) {
convertToAsciidoc( element, "`", "`", doc, innerBlock );
}
else if ( "strong".equalsIgnoreCase( tag ) || "em".equalsIgnoreCase( tag ) || "b".equalsIgnoreCase( tag ) ) {
convertToAsciidoc( element, "**", "**", doc, innerBlock );
}
else if ( "ul".equalsIgnoreCase( tag ) || "ol".equalsIgnoreCase( tag ) ) {
if ( doc.lastIndexOf( "\n" ) != doc.length() - 1 ) {
doc.append( '\n' );
}
convertToAsciidoc( element, "+\n", "", doc, innerBlock );
}
else if ( "li".equalsIgnoreCase( tag ) ) {
convertToAsciidoc( element, "\n * ", "", doc, innerBlock );
}
else if ( "dt".equalsIgnoreCase( tag ) ) {
convertToAsciidoc( element, "+\n**", "**", doc, innerBlock );
}
else if ( "dd".equalsIgnoreCase( tag ) ) {
convertToAsciidoc( element, " ", "", doc, innerBlock );
}
else if ( "span".equalsIgnoreCase( tag ) ) {
if ( element.hasClass( "deprecatedLabel" ) ) {
// label for deprecation, let's make it bold to stand out:
convertToAsciidoc( element, "**", "**", doc, innerBlock );
}
else {
// simply pass to render items:
convertToAsciidoc( element, "", "", doc, innerBlock );
}
}
else {
// if we encounter an element that we are not handling - we want to fail as the result might be missing some details:
throw new IllegalStateException( "Unknown element: " + element );
}
}
else if ( node instanceof TextNode ) {
if ( doc.lastIndexOf( "+\n\n" ) == doc.length() - "+\n\n".length() ) {
// if it's a start of paragraph - remove any leading spaces:
doc.append( ( (TextNode) node ).text().replaceAll( "^\\s+", "" ) );
}
else {
doc.append( ( (TextNode) node ).text() );
}
}
else {
// if we encounter a node that we are not handling - we want to fail as the result might be missing some details:
throw new IllegalStateException( "Unknown node: " + node );
}
}
private void convertToAsciidoc(Element element, String pre, String post, StringBuilder doc, boolean innerBlock) {
doc.append( pre );
for ( Node childNode : element.childNodes() ) {
convertToAsciidoc( childNode, doc, innerBlock );
}
doc.append( post );
}
private String withoutPackagePrefix(String className) {
return className.substring( className.lastIndexOf( '.' ) + 1 );
}
private String packagePrefix(String className) {
return className.substring( 0, className.lastIndexOf( '.' ) );
}
private Optional<Document> obtainJavadoc(String enclosingClass) {
try {
Path docs = javadocsLocation.resolve(
enclosingClass.replace( ".", File.separator ) + ".html"
);
return Optional.of( Jsoup.parse( docs.toFile() ) );
}
catch (IOException e) {
logger.error( "Unable to access javadocs for " + enclosingClass, e );
}
return Optional.empty();
}
private Document locateConstants() {
try {
Path docs = javadocsLocation.resolve( "constant-values.html" );
return Jsoup.parse( docs.toFile() );
}
catch (IOException e) {
logger.error( "Unable to access javadocs `constant-values.html`", e );
throw new IllegalStateException( e );
}
}
}

View File

@ -0,0 +1,40 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
*/
package org.hibernate.orm.properties;
import java.util.Comparator;
import static java.util.Comparator.comparing;
/**
* @author Steve Ebersole
*/
public class SettingDescriptor {
public static final Comparator<SettingDescriptor> BY_NAME = comparing( SettingDescriptor::getName );
private final String name;
private final String javadoc;
public SettingDescriptor(String name, String javadoc) {
this.name = name;
this.javadoc = javadoc;
}
/**
* The name of the setting
*/
public String getName() {
return name;
}
/**
* The Javadoc content
*/
public String getJavadoc() {
return javadoc;
}
}

View File

@ -0,0 +1,331 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
*/
package org.hibernate.orm.properties;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import org.gradle.api.file.Directory;
import org.gradle.api.file.RegularFile;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.nodes.TextNode;
import org.jsoup.select.Elements;
/**
* @author Marko Bekhta
* @author Steve Ebersole
*/
public class SettingsCollector {
public static SortedMap<SettingsDocSection, SortedSet<SettingDescriptor>> collectSettingDescriptors(
Directory javadocDirectory,
Map<String, SettingsDocSection> sections,
String publishedJavadocsUrl) {
final SortedMap<SettingsDocSection, SortedSet<SettingDescriptor>> result = new TreeMap<>( SettingsDocSection.BY_NAME );
// Load the constant-values.html file with Jsoup and start processing it
final Document constantValuesJson = loadConstants( javadocDirectory );
final Elements blockLists = constantValuesJson.select( "ul.block-list" );
for ( int bl = 0; bl < blockLists.size(); bl++ ) {
final Element blockList = blockLists.get( bl );
final String className = blockList.selectFirst( "span" ).text();
final SettingsDocSection docSection = findMatchingDocSection( className, sections );
if ( docSection == null ) {
// does not match any defined sections, skip it
continue;
}
final SortedSet<SettingDescriptor> docSectionSettings = findSettingDescriptors( docSection, result );
final Map<String,Element> classFieldJavadocs = extractClassFieldJavadocs( className, javadocDirectory );
final Element tableDiv = blockList.selectFirst( ".summary-table" );
final Elements constantFqnColumns = tableDiv.select( ".col-first" );
final Elements constantValueColumns = tableDiv.select( ".col-last" );
for ( int c = 0; c < constantFqnColumns.size(); c++ ) {
final Element constantFqnColumn = constantFqnColumns.get( c );
if ( constantFqnColumn.hasClass( "table-header" ) ) {
continue;
}
final String constantFqn = constantFqnColumn.selectFirst( "code" ).id();
final String constantValue = constantValueColumns.get( c ).selectFirst( "code" ).text();
// locate the field javadoc from `classFieldJavadocs`.
// that map is keyed by the simple name of the field, so strip the
// package and class name from `constantFqn` to do the look-up
//
// NOTE : there may be no Javadoc, in which case the Element will be null;
// there is literally no such div in these cases
final String simpleFieldName = constantFqn.substring( constantFqn.lastIndexOf( '.' ) );
final Element fieldJavadocElement = classFieldJavadocs.get( simpleFieldName );
final SettingDescriptor settingDescriptor = new SettingDescriptor(
stripQuotes( constantValue ),
convertFieldJavadocHtmlToAsciidoc(
fieldJavadocElement,
className,
simpleFieldName,
publishedJavadocsUrl
)
// extractJavadoc(
// settingsClassJavadocJson,
// className,
// withoutPackagePrefix( constantFqn ),
// publishedJavadocsUrl
// )
);
docSectionSettings.add( settingDescriptor );
}
}
return result;
}
public static Document loadConstants(Directory javadocDirectory) {
try {
final File constantValuesFile = javadocDirectory.file( "constant-values.html" ).getAsFile();
return Jsoup.parse( constantValuesFile );
}
catch (IOException e) {
throw new IllegalStateException( "Unable to access javadocs `constant-values.html`", e );
}
}
private static SettingsDocSection findMatchingDocSection(
String className,
Map<String, SettingsDocSection> sections) {
for ( Map.Entry<String, SettingsDocSection> entry : sections.entrySet() ) {
if ( entry.getValue().getSettingsClassName().equals( className ) ) {
return entry.getValue();
}
}
return null;
}
private static SortedSet<SettingDescriptor> findSettingDescriptors(
SettingsDocSection docSection,
SortedMap<SettingsDocSection, SortedSet<SettingDescriptor>> map) {
final SortedSet<SettingDescriptor> existing = map.get( docSection );
if ( existing != null ) {
return existing;
}
final SortedSet<SettingDescriptor> created = new TreeSet<>( SettingDescriptor.BY_NAME );
map.put( docSection, created );
return created;
}
private static Map<String, Element> extractClassFieldJavadocs(
String className,
Directory javadocDirectory) {
System.out.println( "Processing Javadoc for " + className );
final Map<String, Element> result = new HashMap<>();
final Document document = loadClassJavadoc( className, javadocDirectory );
final Elements fieldDetailSections = document.select( "section.detail" );
for ( Element fieldDetailSection : fieldDetailSections ) {
final String fieldName = fieldDetailSection.id();
final Element fieldJavadocDiv = fieldDetailSection.selectFirst( "div.block" );
result.put( fieldName, fieldJavadocDiv );
}
return result;
}
private static Document loadClassJavadoc(String enclosingClass, Directory javadocDirectory) {
final String classJavadocFileName = enclosingClass.replace( ".", File.separator ) + ".html";
final RegularFile classJavadocFile = javadocDirectory.file( classJavadocFileName );
try {
return Jsoup.parse( classJavadocFile.getAsFile() );
}
catch (IOException e) {
throw new RuntimeException( "Unable to access javadocs for " + enclosingClass, e );
}
}
private static String stripQuotes(String value) {
if ( value.startsWith( "\"" ) && value.endsWith( "\"" ) ) {
return value.substring( 1, value.length() - 1 );
}
return value;
}
/**
* Convert the DOM representation of the field Javadoc to Asciidoc format
*
* @param fieldJavadocElement The {@code <section class="detail"/>} element for the setting field
* @param className The name of the settings class
* @param simpleFieldName The name of the field defining the setting (relative to {@code className})
* @param publishedJavadocsUrl The (versioned) URL to Javadocs on the doc server
*/
private static String convertFieldJavadocHtmlToAsciidoc(
Element fieldJavadocElement,
String className,
String simpleFieldName,
String publishedJavadocsUrl) {
// todo : here you go Marko :)
return null;
}
private static String extractJavadoc(
Document javadoc,
String className,
String constant,
String publishedJavadocsUrl) {
org.jsoup.nodes.Element block = javadoc.selectFirst( "#" + constant + " + ul li.blockList" );
if ( block != null ) {
for ( org.jsoup.nodes.Element link : block.getElementsByTag( "a" ) ) {
String href = link.attr( "href" );
// only update links if they are not external:
if ( !link.hasClass( "externalLink" ) ) {
if ( href.startsWith( "#" ) ) {
href = withoutPackagePrefix( className ) + ".html" + href;
}
String packagePath = packagePrefix( className ).replace( ".", File.separator );
href = publishedJavadocsUrl + packagePath + "/" + href;
}
else if ( href.contains( "/build/parents/" ) && href.contains( "/apidocs" ) ) {
// means a link was to a class from other module and javadoc plugin generated some external link
// that won't work. So we replace it:
href = publishedJavadocsUrl + href.substring( href.indexOf( "/apidocs" ) + "/apidocs".length() );
}
link.attr( "href", href );
}
Elements result = new Elements();
for ( org.jsoup.nodes.Element child : block.children() ) {
if ( "h4".equalsIgnoreCase( child.tagName() ) || "pre".equalsIgnoreCase( child.tagName() ) ) {
continue;
}
result.add( child );
}
return convertToAsciidoc( result );
}
return "";
}
private static String convertToAsciidoc(Elements elements) {
StringBuilder doc = new StringBuilder( "" );
for ( Element element : elements ) {
convertToAsciidoc( element, doc, false );
}
return doc.toString();
}
private static void convertToAsciidoc(Node node, StringBuilder doc, boolean innerBlock) {
if ( node instanceof Element ) {
Element element = (Element) node;
String tag = element.tagName();
if ( "p".equalsIgnoreCase( tag ) || "div".equalsIgnoreCase( tag ) || "dl".equalsIgnoreCase( tag ) ) {
if ( doc.length() != 0 ) {
if ( !innerBlock ) {
doc.append( "\n+" );
}
doc.append( "\n\n" );
}
boolean deprecation = element.hasClass( "deprecationBlock" );
if ( deprecation ) {
doc.append( "+\n[WARNING]\n====\n" );
}
for ( Node child : element.childNodes() ) {
convertToAsciidoc( child, doc, deprecation );
}
doc.append( '\n' );
if ( deprecation ) {
doc.append( "====\n" );
}
}
else if ( "a".equalsIgnoreCase( tag ) ) {
convertToAsciidoc( element, "link:" + element.attr( "href" ) + "[", "]", doc, innerBlock );
}
else if ( "code".equalsIgnoreCase( tag ) ) {
convertToAsciidoc( element, "`", "`", doc, innerBlock );
}
else if ( "strong".equalsIgnoreCase( tag ) || "em".equalsIgnoreCase( tag ) || "b".equalsIgnoreCase( tag ) ) {
convertToAsciidoc( element, "**", "**", doc, innerBlock );
}
else if ( "ul".equalsIgnoreCase( tag ) || "ol".equalsIgnoreCase( tag ) ) {
if ( doc.lastIndexOf( "\n" ) != doc.length() - 1 ) {
doc.append( '\n' );
}
convertToAsciidoc( element, "+\n", "", doc, innerBlock );
}
else if ( "li".equalsIgnoreCase( tag ) ) {
convertToAsciidoc( element, "\n * ", "", doc, innerBlock );
}
else if ( "dt".equalsIgnoreCase( tag ) ) {
convertToAsciidoc( element, "+\n**", "**", doc, innerBlock );
}
else if ( "dd".equalsIgnoreCase( tag ) ) {
convertToAsciidoc( element, " ", "", doc, innerBlock );
}
else if ( "span".equalsIgnoreCase( tag ) ) {
if ( element.hasClass( "deprecatedLabel" ) ) {
// label for deprecation, let's make it bold to stand out:
convertToAsciidoc( element, "**", "**", doc, innerBlock );
}
else {
// simply pass to render items:
convertToAsciidoc( element, "", "", doc, innerBlock );
}
}
else {
// if we encounter an element that we are not handling - we want to fail as the result might be missing some details:
throw new IllegalStateException( "Unknown element: " + element );
}
}
else if ( node instanceof TextNode ) {
if ( doc.lastIndexOf( "+\n\n" ) == doc.length() - "+\n\n".length() ) {
// if it's a start of paragraph - remove any leading spaces:
doc.append( ( (TextNode) node ).text().replaceAll( "^\\s+", "" ) );
}
else {
doc.append( ( (TextNode) node ).text() );
}
}
else {
// if we encounter a node that we are not handling - we want to fail as the result might be missing some details:
throw new IllegalStateException( "Unknown node: " + node );
}
}
private static void convertToAsciidoc(
Element element,
String pre,
String post,
StringBuilder doc,
boolean innerBlock) {
doc.append( pre );
for ( Node childNode : element.childNodes() ) {
convertToAsciidoc( childNode, doc, innerBlock );
}
doc.append( post );
}
private static String withoutPackagePrefix(String className) {
return className.substring( className.lastIndexOf( '.' ) + 1 );
}
private static String packagePrefix(String className) {
return className.substring( 0, className.lastIndexOf( '.' ) );
}
}

View File

@ -0,0 +1,102 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
*/
package org.hibernate.orm.properties;
import javax.inject.Inject;
import org.gradle.api.DefaultTask;
import org.gradle.api.NamedDomainObjectContainer;
import org.gradle.api.Project;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.IgnoreEmptyDirectories;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputDirectory;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.Nested;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;
import org.hibernate.orm.ReleaseFamilyIdentifier;
import static org.hibernate.orm.properties.SettingsDocumentationPlugin.TASK_GROUP_NAME;
/**
* @author Steve Ebersole
*/
public class SettingsDocGeneratorTask extends DefaultTask {
public static final String TASK_NAME = "generateSettingsDoc";
private final DirectoryProperty javadocDirectory;
private final Property<ReleaseFamilyIdentifier> releaseFamily;
private final Property<String> publishedDocsUrl;
private final NamedDomainObjectContainer<SettingsDocSection> sections;
private final RegularFileProperty outputFile;
@Inject
public SettingsDocGeneratorTask(Project project) {
setGroup( TASK_GROUP_NAME );
setDescription( "Collects descriptions of Hibernate configuration properties in preparation for inclusion in the User Guide" );
javadocDirectory = project.getObjects().directoryProperty();
javadocDirectory.convention( project.getLayout().getBuildDirectory().dir( "javadocs" ) );
releaseFamily = project.getObjects().property( ReleaseFamilyIdentifier.class );
releaseFamily.convention( project.provider( () -> ReleaseFamilyIdentifier.parse( project.getVersion().toString() ) ) );
publishedDocsUrl = project.getObjects().property( String.class );
publishedDocsUrl.convention( "https://docs.jboss.org/hibernate/orm" );
sections = project.getObjects().domainObjectContainer( SettingsDocSection.class, SettingsDocSection::create );
outputFile = project.getObjects().fileProperty();
outputFile.convention( project.getLayout().getBuildDirectory().file( "asciidoc/fragments/config-settings.adoc" ) );
}
@InputDirectory
@IgnoreEmptyDirectories
public DirectoryProperty getJavadocDirectory() {
return javadocDirectory;
}
@Input
public Property<ReleaseFamilyIdentifier> getReleaseFamily() {
return releaseFamily;
}
// @Nested
@Internal
public NamedDomainObjectContainer<SettingsDocSection> getSections() {
return sections;
}
@OutputFile
public RegularFileProperty getOutputFile() {
return outputFile;
}
@TaskAction
public void generateSettingsDocumentation() {
final String publishedJavadocUrl = publishedDocsUrl.get()
+ "/"
+ releaseFamily.get().getFamilyVersion()
+ "/javadocs/";
AsciiDocWriter.writeToFile(
SettingsCollector.collectSettingDescriptors(
javadocDirectory.get(),
sections.getAsMap(),
publishedJavadocUrl
),
outputFile.get(),
getProject()
);
}
}

View File

@ -0,0 +1,60 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
*/
package org.hibernate.orm.properties;
import java.util.Comparator;
import static java.util.Comparator.comparing;
/**
* DSL extension for defining a section in the settings appendix in the User Guide.
* <p/>
* Specifies the settings class to match, and identifies which module (by name) the
* settings class from.
*
* @author Steve Ebersole
*/
public class SettingsDocSection {
public static final Comparator<SettingsDocSection> BY_NAME = comparing( SettingsDocSection::getName );
/**
* Factory for SettingsDocSection instances
*/
public static SettingsDocSection create(String name) {
return new SettingsDocSection( name );
}
private final String name;
// todo : do we ever care about multiple settings-classes for a single project?
private String projectPath;
private String settingsClassName;
public SettingsDocSection(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String getProjectPath() {
return projectPath;
}
public void setProjectPath(String projectPath) {
this.projectPath = projectPath;
}
public String getSettingsClassName() {
return settingsClassName;
}
public void setSettingsClassName(String settingsClassName) {
this.settingsClassName = settingsClassName;
}
}

View File

@ -0,0 +1,24 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.properties;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
/**
* Integrates collection of documentation about Hibernate configuration properties
* from the Javadoc of the project, and generates an Asciidoc document from it
* which is then included into the User Guide.
*/
public class SettingsDocumentationPlugin implements Plugin<Project> {
public static final String TASK_GROUP_NAME = "documentation";
@Override
public void apply(Project project) {
project.getTasks().register( SettingsDocGeneratorTask.TASK_NAME, SettingsDocGeneratorTask.class );
}
}

View File

@ -0,0 +1,17 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
*/
/**
* Collects Javadoc information about Hibernate configuration properties
* for use in the User Guide
*
* @see org.hibernate.orm.properties.SettingsDocumentationPlugin
*
* @author Marko Bekhta
* @author Steve Ebersole
*/
package org.hibernate.orm.properties;

View File

@ -18,195 +18,9 @@ apply plugin: 'idea'
idea.module { idea.module {
} }
configurations {
core
testing
envers
spatial
agroal
c3p0
hikaricp
proxool
vibur
jcache
jpamodelgen
javadocClasspath {
description = 'Class files for the javadoc to be built'
resolutionStrategy.capabilitiesResolution.withCapability('org.junit.jupiter:junit-jupiter-params:5.7.1') { details ->
details.select( details.candidates.first() ).because( 'first' )
}
extendsFrom core
extendsFrom testing
extendsFrom envers
extendsFrom spatial
extendsFrom agroal
extendsFrom c3p0
extendsFrom hikaricp
extendsFrom proxool
extendsFrom vibur
extendsFrom jcache
extendsFrom jpamodelgen
}
javadocSources {
description = 'Source files to be built by the javadoc tool'
}
}
// skip building this when `build` task is run from root, as many of our CI jobs do // skip building this when `build` task is run from root, as many of our CI jobs do
tasks.build.dependsOn.clear() tasks.build.dependsOn.clear()
dependencies {
attributesSchema { schema ->
schema.attribute(Bundling.BUNDLING_ATTRIBUTE) { matchStrategy ->
final def nameComparator = Comparator.comparing(
new Function<Bundling,String>() {
@Override
String apply(Bundling o) {
return o.name
}
}
)
matchStrategy.ordered(new Comparator<Bundling>() {
@Override
int compare(Bundling o1, Bundling o2) {
if ( Objects.equals( o1, o2 ) ) {
return 0;
}
if ( o1 == null ) {
return 1;
}
if ( o2 == null ) {
return -1;
}
if ( o1.name == Bundling.EMBEDDED ) {
return -1;
}
if ( o2.name == Bundling.EMBEDDED ) {
return 1;
}
return nameComparator.compare(o1,o2)
}
} )
}
}
core project( ':hibernate-core' )
javadocSources project( path: ':hibernate-core', configuration: 'javadocSources' )
testing project( ':hibernate-testing' )
javadocSources project( path: ':hibernate-testing', configuration: 'javadocSources' )
envers project( ':hibernate-envers' )
javadocSources project( path: ':hibernate-envers', configuration: 'javadocSources' )
spatial project( ':hibernate-spatial' )
javadocSources project( path: ':hibernate-spatial', configuration: 'javadocSources' )
agroal project( ':hibernate-agroal' )
javadocSources project( path: ':hibernate-agroal', configuration: 'javadocSources' )
c3p0 project( ':hibernate-c3p0' )
javadocSources project( path: ':hibernate-c3p0', configuration: 'javadocSources' )
hikaricp project( ':hibernate-hikaricp' )
javadocSources project( path: ':hibernate-hikaricp', configuration: 'javadocSources' )
proxool project( ':hibernate-proxool' )
javadocSources project( path: ':hibernate-proxool', configuration: 'javadocSources' )
vibur project( ':hibernate-vibur' )
javadocSources project( path: ':hibernate-vibur', configuration: 'javadocSources' )
jcache project( ':hibernate-jcache' )
javadocSources project( path: ':hibernate-jcache', configuration: 'javadocSources' )
jpamodelgen project( ':hibernate-jpamodelgen' )
javadocSources project( path: ':hibernate-jpamodelgen', configuration: 'javadocSources' )
javadocClasspath libs.loggingAnnotations
javadocClasspath jakartaLibs.validation
javadocClasspath jakartaLibs.cdi
javadocClasspath jakartaLibs.jacc
javadocClasspath jakartaLibs.jsonbApi
javadocClasspath libs.ant
javadocClasspath dbLibs.postgresql
javadocClasspath libs.jackson
javadocClasspath gradleApi()
javadocClasspath libs.jacksonXml
javadocClasspath dbLibs.oracle
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// aggregated JavaDoc
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def aggregateJavadocsTask = tasks.register( "aggregateJavadocs", Javadoc ) {
description = 'Builds an aggregated JavaDoc across all ORM sub-projects'
final int currentYear = new GregorianCalendar().get( Calendar.YEAR )
destinationDir = mkdir( new File( (File) project.buildDir, 'documentation/javadocs' ) )
source configurations.javadocSources
classpath += configurations.javadocClasspath
// exclude any generated sources and internal packages
exclude '**/generated-src/**'
exclude '**/internal/**'
include '**/*.java'
// apply standard config
maxMemory = '512m'
configure( options ) {
overview = 'src/release/javadoc/overview.html'
stylesheetFile = new File( projectDir, 'src/release/javadoc/stylesheet.css' )
windowTitle = 'Hibernate JavaDocs'
docTitle = "Hibernate JavaDoc ($project.version)"
bottom = "Copyright &copy; 2001-$currentYear <a href=\"https://redhat.com\">Red Hat, Inc.</a> All Rights Reserved."
use = true
options.encoding = 'UTF-8'
links = [
'https://docs.oracle.com/en/java/javase/11/docs/api/',
'https://docs.jboss.org/hibernate/beanvalidation/spec/2.0/api/',
'https://docs.jboss.org/cdi/api/2.0/',
'https://jakarta.ee/specifications/platform/8/apidocs/'
]
options.addStringOption( 'Xdoclint:none', '-quiet' )
if ( jdkVersions.explicit ) {
options.setJFlags(
getProperty( 'toolchain.javadoc.jvmargs' ).toString().
split( ' ' ).toList().findAll( { !it.isEmpty() } )
)
}
}
if ( jdkVersions.explicit ) {
// Display version of Java tools
doFirst {
if ( javadocTool.present ) {
logger.lifecycle "Aggregating javadoc with '${javadocTool.get().metadata.installationPath}'"
}
}
}
}
def stageIntegrationGuideTask = tasks.register( "stageIntegrationGuide", Copy ) { def stageIntegrationGuideTask = tasks.register( "stageIntegrationGuide", Copy ) {
group "Release" group "Release"