View Javadoc
1   package org.apache.maven.plugins.javadoc;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.nio.charset.Charset;
25  import java.nio.charset.StandardCharsets;
26  import java.nio.file.DirectoryStream;
27  import java.nio.file.Files;
28  import java.nio.file.Path;
29  import java.util.ArrayList;
30  import java.util.Collection;
31  import java.util.Collections;
32  import java.util.List;
33  
34  import org.apache.maven.reporting.MavenReportException;
35  import org.codehaus.plexus.languages.java.version.JavaVersion;
36  import org.codehaus.plexus.util.StringUtils;
37  import org.codehaus.plexus.util.cli.Commandline;
38  
39  /**
40   * Helper class to compute and write data used to detect a
41   * stale javadoc.
42   */
43  public class StaleHelper
44  {
45  
46      /**
47       * Compute the data used to detect a stale javadoc
48       *
49       * @param cmd the command line
50       * @return the stale data
51       * @throws MavenReportException if an error occurs
52       */
53      public static String getStaleData( Commandline cmd )
54              throws MavenReportException
55      {
56          try
57          {
58              List<String> ignored = new ArrayList<>();
59              List<String> options = new ArrayList<>();
60              Path dir = cmd.getWorkingDirectory().toPath().toAbsolutePath().normalize();
61              String[] args = cmd.getArguments();
62              Collections.addAll( options, args );
63              
64              final Charset cs;
65              if ( JavaVersion.JAVA_SPECIFICATION_VERSION.isAtLeast( "9" )
66                  && JavaVersion.JAVA_SPECIFICATION_VERSION.isBefore( "12" ) )
67              {
68                  cs = StandardCharsets.UTF_8;
69              }
70              else
71              {
72                  cs = Charset.defaultCharset();
73              }
74              
75              for ( String arg : args )
76              {
77                  if ( arg.startsWith( "@" ) )
78                  {
79                      String name = arg.substring( 1 );
80                      options.addAll( Files.readAllLines( dir.resolve( name ), cs ) );
81                      ignored.add( name );
82                  }
83              }
84              List<String> state = new ArrayList<>( options );
85              boolean cp = false;
86              boolean sp = false;
87              for ( String arg : options )
88              {
89                  if ( cp )
90                  {
91                      String s = unquote( arg );
92                      for ( String ps : s.split( File.pathSeparator ) )
93                      {
94                          Path p = dir.resolve( ps );
95                          state.add( p + " = " + lastmod( p ) );
96                      }
97                  }
98                  else if ( sp )
99                  {
100                     String s = unquote( arg );
101                     for ( String ps : s.split( File.pathSeparator ) )
102                     {
103                         Path p = dir.resolve( ps );
104                         for ( Path c : walk( p ) )
105                         {
106                             if ( Files.isRegularFile( c ) )
107                             {
108                                 state.add( c + " = " + lastmod( c ) );
109                             }
110                         }
111                         state.add( p + " = " + lastmod( p ) );
112                     }
113                 }
114                 cp = "-classpath".equals( arg );
115                 sp = "-sourcepath".equals( arg );
116             }
117             for ( Path p : walk( dir ) )
118             {
119                 if ( Files.isRegularFile( p ) && !ignored.contains( p.getFileName().toString() ) )
120                 {
121                     state.add( p + " = " + lastmod( p ) );
122                 }
123             }
124             return StringUtils.join( state.iterator(), SystemUtils.LINE_SEPARATOR );
125         }
126         catch ( Exception e )
127         {
128             throw new MavenReportException( "Unable to compute stale date", e );
129         }
130     }
131 
132     /**
133      * Write the data used to detect a stale javadoc
134      *
135      * @param cmd the command line
136      * @param path the stale data path
137      * @throws MavenReportException if an error occurs
138      */
139     public static void writeStaleData( Commandline cmd, Path path )
140             throws MavenReportException
141     {
142         try
143         {
144             String curdata = getStaleData( cmd );
145             Files.createDirectories( path.getParent() );
146             Files.write( path, Collections.singleton( curdata ), Charset.defaultCharset() );
147         }
148         catch ( IOException e )
149         {
150             throw new MavenReportException( "Error checking stale data", e );
151         }
152     }
153 
154     private static Collection<Path> walk( Path dir )
155     {
156         Collection<Path> paths = new ArrayList<>();
157         try ( DirectoryStream<Path> directoryStream = Files.newDirectoryStream( dir ) )
158         {
159             for ( Path p : directoryStream )
160             {
161                 paths.add( p );
162             }
163             return paths;
164         }
165         catch ( IOException e )
166         {
167             throw new RuntimeException( e );
168         }
169     }
170 
171     private static String unquote( String s )
172     {
173         if ( s.startsWith( "'" ) && s.endsWith( "'" ) )
174         {
175             return s.substring( 1, s.length() - 1 ).replaceAll( "\\\\'", "'" );
176         }
177         else
178         {
179             return s;
180         }
181     }
182 
183     private static long lastmod( Path p )
184     {
185         try
186         {
187             return Files.getLastModifiedTime( p ).toMillis();
188         }
189         catch ( IOException e )
190         {
191             return 0;
192         }
193     }
194 
195 }