From f92b508c26945a0e728fb3b49e87fe216401c9c1 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 17 Dec 2019 06:59:16 +0100 Subject: [PATCH] [MJAVADOC-626] Add a stale javadoc detection mechanism (#33) * [MJAVADOC-626] Add a stale javadoc detection mechanism * Revert the use of Java 8 --- .../plugins/javadoc/AbstractJavadocMojo.java | 83 ++++++++ .../maven/plugins/javadoc/StaleHelper.java | 181 ++++++++++++++++++ 2 files changed, 264 insertions(+) create mode 100644 src/main/java/org/apache/maven/plugins/javadoc/StaleHelper.java 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 7e31c156..2b6a5909 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 // ---------------------------------------------------------------------- @@ -5713,6 +5725,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 00000000..72b2e480 --- /dev/null +++ b/src/main/java/org/apache/maven/plugins/javadoc/StaleHelper.java @@ -0,0 +1,181 @@ +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.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 org.apache.maven.reporting.MavenReportException; +import org.codehaus.plexus.util.FileUtils; +import org.codehaus.plexus.util.StringUtils; +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 ); + options.addAll( Files.readAllLines( dir.resolve( name ), StandardCharsets.UTF_8 ) ); + ignored.add( name ); + } + } + List state = new ArrayList<>( options ); + boolean cp = false; + boolean sp = false; + for ( String arg : options ) + { + if ( cp ) + { + String s = unquote( arg ); + for ( String ps : s.split( File.pathSeparator ) ) + { + Path p = dir.resolve( ps ); + state.add( p + " = " + lastmod( p ) ); + } + } + else if ( sp ) + { + String s = unquote( arg ); + 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 ); + } + 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 ) + { + 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() ); + FileUtils.fileWrite( path.toFile(), null /* platform encoding */, curdata ); + } + catch ( IOException e ) + { + throw new MavenReportException( "Error checking stale data", e ); + } + } + + private static Collection walk( Path dir ) + { + try + { + Collection paths = new ArrayList<>(); + for ( Path p : Files.newDirectoryStream( dir ) ) + { + paths.add( p ); + } + return paths; + } + 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; + } + } + +}