From ca9098fda48d7d897909b6f4d194ce8e04ea8482 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Mon, 28 Oct 2019 10:12:25 +0100 Subject: [PATCH 1/2] [MJAVADOC-626] Add a stale javadoc detection mechanism --- pom.xml | 2 +- .../plugins/javadoc/AbstractJavadocMojo.java | 83 +++++++++ .../maven/plugins/javadoc/StaleHelper.java | 169 ++++++++++++++++++ 3 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/apache/maven/plugins/javadoc/StaleHelper.java diff --git a/pom.xml b/pom.xml index 0bb261631..2ffa76319 100644 --- a/pom.xml +++ b/pom.xml @@ -66,7 +66,7 @@ under the License. - 7 + 8 3.0 1.7 1.7.4 diff --git a/src/main/java/org/apache/maven/plugins/javadoc/AbstractJavadocMojo.java b/src/main/java/org/apache/maven/plugins/javadoc/AbstractJavadocMojo.java index 9250cd05d..05ee2962b 100644 --- a/src/main/java/org/apache/maven/plugins/javadoc/AbstractJavadocMojo.java +++ b/src/main/java/org/apache/maven/plugins/javadoc/AbstractJavadocMojo.java @@ -1736,6 +1736,18 @@ public abstract class AbstractJavadocMojo @Parameter private Map jdkToolchain; + /** + *

+ * Location of the file used to store the state of the previous javadoc run. + * This is used to skip the generation if nothing has changed. + *

+ * + * @since 3.2.0 + */ + @Parameter( property = "staleDataPath", + defaultValue = "${project.build.directory}/maven-javadoc-plugin-stale-data.txt" ) + private File staleDataPath; + // ---------------------------------------------------------------------- // protected methods // ---------------------------------------------------------------------- @@ -5701,6 +5713,77 @@ private void addTagletsFromTagletArtifacts( List arguments ) * @throws MavenReportException if any errors occur */ private void executeJavadocCommandLine( Commandline cmd, File javadocOutputDirectory ) + throws MavenReportException + { + if ( staleDataPath != null ) + { + if ( !isUpToDate( cmd ) ) + { + doExecuteJavadocCommandLine( cmd, javadocOutputDirectory ); + StaleHelper.writeStaleData( cmd, staleDataPath.toPath() ); + } + } + else + { + doExecuteJavadocCommandLine( cmd, javadocOutputDirectory ); + } + } + + /** + * Check if the javadoc is uptodate or not + * + * @param cmd not null + * @return true is the javadoc is uptodate, false otherwise + * @throws MavenReportException if any error occur + */ + private boolean isUpToDate( Commandline cmd ) + throws MavenReportException + { + try + { + String curdata = StaleHelper.getStaleData( cmd ); + Path cacheData = staleDataPath.toPath(); + String prvdata; + if ( Files.isRegularFile( cacheData ) ) + { + prvdata = new String( Files.readAllBytes( cacheData ), StandardCharsets.UTF_8 ); + } + else + { + prvdata = null; + } + if ( curdata.equals( prvdata ) ) + { + getLog().info( "Skipping javadoc generation, everything is up to date." ); + return true; + } + else + { + if ( prvdata == null ) + { + getLog().info( "No previous run data found, generating javadoc." ); + } + else + { + getLog().info( "Configuration changed, re-generating javadoc." ); + } + } + } + catch ( IOException e ) + { + throw new MavenReportException( "Error checking uptodate status", e ); + } + return false; + } + + /** + * Execute the Javadoc command line + * + * @param cmd not null + * @param javadocOutputDirectory not null + * @throws MavenReportException if any errors occur + */ + private void doExecuteJavadocCommandLine( Commandline cmd, File javadocOutputDirectory ) throws MavenReportException { if ( getLog().isDebugEnabled() ) diff --git a/src/main/java/org/apache/maven/plugins/javadoc/StaleHelper.java b/src/main/java/org/apache/maven/plugins/javadoc/StaleHelper.java new file mode 100644 index 000000000..565eb604a --- /dev/null +++ b/src/main/java/org/apache/maven/plugins/javadoc/StaleHelper.java @@ -0,0 +1,169 @@ +package org.apache.maven.plugins.javadoc; + +/* + * 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. + */ + +import java.io.File; +import java.io.IOException; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; + +import org.apache.maven.reporting.MavenReportException; +import org.codehaus.plexus.util.cli.Commandline; + +/** + * Helper class to compute and write data used to detect a + * stale javadoc. + */ +public class StaleHelper +{ + + /** + * Compute the data used to detect a stale javadoc + * + * @param cmd the command line + * @return the stale data + * @throws MavenReportException if an error occurs + */ + public static String getStaleData( Commandline cmd ) + throws MavenReportException + { + try + { + List ignored = new ArrayList<>(); + List options = new ArrayList<>(); + Path dir = cmd.getWorkingDirectory().toPath().toAbsolutePath().normalize(); + String[] args = cmd.getCommandline(); + Collections.addAll( options, args ); + for ( String arg : args ) + { + if ( arg.startsWith( "@" ) ) + { + String name = arg.substring( 1 ); + Files.lines( dir.resolve( name ) ).forEachOrdered( options::add ); + ignored.add( name ); + } + } + List state = new ArrayList<>( options ); + boolean cp = false; + boolean sp = false; + for ( String arg : options ) + { + if ( cp ) + { + String s = unquote( arg ); + Stream.of( s.split( File.pathSeparator ) ) + .map( dir::resolve ) + .map( p -> p + " = " + lastmod( p ) ) + .forEachOrdered( state::add ); + } + else if ( sp ) + { + String s = unquote( arg ); + Stream.of( s.split( File.pathSeparator ) ) + .map( dir::resolve ) + .flatMap( StaleHelper::walk ) + .filter( Files::isRegularFile ) + .map( p -> p + " = " + lastmod( p ) ) + .forEachOrdered( state::add ); + } + cp = "-classpath".equals( arg ); + sp = "-sourcepath".equals( arg ); + } + walk( dir ) + .filter( Files::isRegularFile ) + .filter( p -> !ignored.contains( p.getFileName().toString() ) ) + .map( p -> p + " = " + lastmod( p ) ) + .forEachOrdered( state::add ); + + return String.join( SystemUtils.LINE_SEPARATOR, state ); + } + catch ( Exception e ) + { + throw new MavenReportException( "Unable to compute stale date", e ); + } + } + + /** + * Write the data used to detect a stale javadoc + * + * @param cmd the command line + * @param path the stale data path + * @throws MavenReportException if an error occurs + */ + public static void writeStaleData( Commandline cmd, Path path ) + throws MavenReportException + { + try + { + String curdata = getStaleData( cmd ); + Files.createDirectories( path.getParent() ); + try ( Writer w = Files.newBufferedWriter( path ) ) + { + w.append( curdata ); + } + } + catch ( IOException e ) + { + throw new MavenReportException( "Error checking stale data", e ); + } + } + + private static Stream walk( Path dir ) + { + try + { + return Files.walk( dir ); + } + catch ( IOException e ) + { + throw new RuntimeException( e ); + } + } + + private static String unquote( String s ) + { + if ( s.startsWith( "'" ) && s.endsWith( "'" ) ) + { + return s.substring( 1, s.length() - 1 ).replaceAll( "\\\\'", "'" ); + } + else + { + return s; + } + } + + private static long lastmod( Path p ) + { + try + { + return Files.getLastModifiedTime( p ).toMillis(); + } + catch ( IOException e ) + { + return 0; + } + } + +} From 3b082a1a35e0e02a17ad7a83577bbc66036d0839 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Mon, 28 Oct 2019 16:47:28 +0100 Subject: [PATCH 2/2] Revert the use of Java 8 --- pom.xml | 2 +- .../maven/plugins/javadoc/StaleHelper.java | 64 +++++++++++-------- 2 files changed, 39 insertions(+), 27 deletions(-) diff --git a/pom.xml b/pom.xml index 2ffa76319..0bb261631 100644 --- a/pom.xml +++ b/pom.xml @@ -66,7 +66,7 @@ under the License. - 8 + 7 3.0 1.7 1.7.4 diff --git a/src/main/java/org/apache/maven/plugins/javadoc/StaleHelper.java b/src/main/java/org/apache/maven/plugins/javadoc/StaleHelper.java index 565eb604a..72b2e4808 100644 --- a/src/main/java/org/apache/maven/plugins/javadoc/StaleHelper.java +++ b/src/main/java/org/apache/maven/plugins/javadoc/StaleHelper.java @@ -21,15 +21,17 @@ import java.io.File; import java.io.IOException; -import java.io.Writer; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.stream.Stream; import org.apache.maven.reporting.MavenReportException; +import org.codehaus.plexus.util.FileUtils; +import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.cli.Commandline; /** @@ -61,7 +63,7 @@ public static String getStaleData( Commandline cmd ) if ( arg.startsWith( "@" ) ) { String name = arg.substring( 1 ); - Files.lines( dir.resolve( name ) ).forEachOrdered( options::add ); + options.addAll( Files.readAllLines( dir.resolve( name ), StandardCharsets.UTF_8 ) ); ignored.add( name ); } } @@ -73,31 +75,39 @@ public static String getStaleData( Commandline cmd ) if ( cp ) { String s = unquote( arg ); - Stream.of( s.split( File.pathSeparator ) ) - .map( dir::resolve ) - .map( p -> p + " = " + lastmod( p ) ) - .forEachOrdered( state::add ); + for ( String ps : s.split( File.pathSeparator ) ) + { + Path p = dir.resolve( ps ); + state.add( p + " = " + lastmod( p ) ); + } } else if ( sp ) { String s = unquote( arg ); - Stream.of( s.split( File.pathSeparator ) ) - .map( dir::resolve ) - .flatMap( StaleHelper::walk ) - .filter( Files::isRegularFile ) - .map( p -> p + " = " + lastmod( p ) ) - .forEachOrdered( state::add ); + for ( String ps : s.split( File.pathSeparator ) ) + { + Path p = dir.resolve( ps ); + for ( Path c : walk( p ) ) + { + if ( Files.isRegularFile( c ) ) + { + state.add( c + " = " + lastmod( c ) ); + } + } + state.add( p + " = " + lastmod( p ) ); + } } cp = "-classpath".equals( arg ); sp = "-sourcepath".equals( arg ); } - walk( dir ) - .filter( Files::isRegularFile ) - .filter( p -> !ignored.contains( p.getFileName().toString() ) ) - .map( p -> p + " = " + lastmod( p ) ) - .forEachOrdered( state::add ); - - return String.join( SystemUtils.LINE_SEPARATOR, state ); + for ( Path p : walk( dir ) ) + { + if ( Files.isRegularFile( p ) && !ignored.contains( p.getFileName().toString() ) ) + { + state.add( p + " = " + lastmod( p ) ); + } + } + return StringUtils.join( state.iterator(), SystemUtils.LINE_SEPARATOR ); } catch ( Exception e ) { @@ -119,10 +129,7 @@ public static void writeStaleData( Commandline cmd, Path path ) { String curdata = getStaleData( cmd ); Files.createDirectories( path.getParent() ); - try ( Writer w = Files.newBufferedWriter( path ) ) - { - w.append( curdata ); - } + FileUtils.fileWrite( path.toFile(), null /* platform encoding */, curdata ); } catch ( IOException e ) { @@ -130,11 +137,16 @@ public static void writeStaleData( Commandline cmd, Path path ) } } - private static Stream walk( Path dir ) + private static Collection walk( Path dir ) { try { - return Files.walk( dir ); + Collection paths = new ArrayList<>(); + for ( Path p : Files.newDirectoryStream( dir ) ) + { + paths.add( p ); + } + return paths; } catch ( IOException e ) {