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