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.rat.tools;
20  
21  import java.io.File;
22  import java.io.FileNotFoundException;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.OutputStreamWriter;
26  import java.io.Writer;
27  import java.nio.charset.StandardCharsets;
28  import java.nio.file.Files;
29  import java.util.ArrayList;
30  import java.util.Arrays;
31  import java.util.Collection;
32  import java.util.List;
33  import java.util.Map;
34  import java.util.function.Predicate;
35  import java.util.function.Supplier;
36  import java.util.stream.Collectors;
37  
38  
39  import org.apache.commons.io.IOUtils;
40  import org.apache.commons.lang3.StringUtils;
41  import org.apache.rat.OptionCollection;
42  import org.apache.rat.commandline.Arg;
43  import org.apache.rat.utils.DefaultLog;
44  
45  import static java.lang.String.format;
46  
47  /**
48   * A simple tool to convert CLI options into an Ant report base class.
49   */
50  public final class AntDocumentation {
51      /** The directory to write to. */
52      private final File outputDir;
53  
54      /**
55       * Creates apt documentation files for Ant.
56       * Requires 1 argument:
57       * <ol>
58       *     <li>the directory in which to write the documentation files.</li>
59       * </ol>
60       * @param args the arguments.
61       * @throws IOException on error
62       */
63      public static void main(final String[] args) throws IOException {
64  
65          if (args.length == 0) {
66              System.err.println("Output directory must be specified");
67              System.exit(1);
68          }
69          File outputDir = new File(args[0]);
70          if (outputDir.exists()) {
71              if (!outputDir.isDirectory()) {
72                  DefaultLog.getInstance().error(format("%s is not a directory", args[0]));
73                  System.exit(1);
74              }
75          } else {
76              if (!outputDir.mkdirs()) {
77                  DefaultLog.getInstance().error(format("Can not create directory %s", args[0]));
78                  System.exit(1);
79              }
80          }
81          new AntDocumentation(outputDir).execute();
82      }
83  
84     private AntDocumentation(final File outputDir) {
85          this.outputDir = outputDir;
86      }
87  
88      public void execute() {
89          List<AntOption> options = Arg.getOptions().getOptions().stream().filter(AntGenerator.getFilter()).map(AntOption::new)
90                  .collect(Collectors.toList());
91  
92          writeAttributes(options);
93          writeElements(options);
94          printValueTypes();
95      }
96  
97      public void writeAttributes(final List<AntOption> options) {
98          File f = new File(outputDir, "report_attributes.txt");
99          try (Writer out = new OutputStreamWriter(Files.newOutputStream(f.toPath()), StandardCharsets.UTF_8)) {
100             printOptions(out, options, AntOption::isAttribute,
101                     "The attribute value types are listed in a table at the bottom of this page.");
102         } catch (IOException e) {
103             throw new RuntimeException(e);
104         }
105     }
106 
107     public void writeElements(final List<AntOption> options) {
108         File f = new File(outputDir, "report_elements.txt");
109         try (Writer out = new OutputStreamWriter(Files.newOutputStream(f.toPath()), StandardCharsets.UTF_8)) {
110             printOptions(out, options, AntOption::isElement,
111                     "The element value types are listed in a table at the bottom of this page.");
112         } catch (IOException e) {
113             throw new RuntimeException(e);
114         }
115     }
116     private void printOptions(final Writer out, final List<AntOption> options,
117                               final Predicate<AntOption> typeFilter, final String tableCaption) throws IOException {
118         boolean hasDeprecated = options.stream().anyMatch(typeFilter.and(AntOption::isDeprecated));
119 
120         if (hasDeprecated) {
121             AptFormat.writeHeader(out, 2, "Current");
122         }
123 
124         List<List<String>> table = new ArrayList<>();
125         table.add(Arrays.asList("Name", "Description", "Value Type", "Required"));
126         options.stream().filter(typeFilter.and(o -> !o.isDeprecated()))
127                 .map(o -> Arrays.asList(o.getName(), o.getDescription(),
128                         o.hasArg() ? StringUtils.defaultIfEmpty(o.getArgName(), "String") : "boolean",
129                         o.isRequired() ? "true" : "false"))
130                 .forEach(table::add);
131 
132         AptFormat.writeTable(out, table, "*--+--+--+--+", tableCaption);
133 
134         if (hasDeprecated) {
135             AptFormat.writeHeader(out, 2, "Deprecated ");
136 
137             table.clear();
138             table.add(Arrays.asList("Name", "Description", "Argument Type", "Deprecated"));
139 
140             options.stream().filter(typeFilter.and(AntOption::isDeprecated))
141                     .map(o -> Arrays.asList(o.getName(), o.getDescription(),
142                             o.hasArg() ? StringUtils.defaultIfEmpty(o.getArgName(), "String") : "boolean",
143                             o.getDeprecated()))
144                     .forEach(table::add);
145 
146             AptFormat.writeTable(out, table, "*--+--+--+--+", tableCaption);
147         }
148     }
149 
150     private void printValueTypes() {
151 
152         File f = new File(outputDir, "report_arg_types.txt");
153         try (Writer writer = new OutputStreamWriter(Files.newOutputStream(f.toPath()), StandardCharsets.UTF_8)) {
154 
155         List<List<String>> table = new ArrayList<>();
156         table.add(Arrays.asList("Value Type", "Description"));
157 
158         for (Map.Entry<String, Supplier<String>> argInfo : OptionCollection.getArgumentTypes().entrySet()) {
159             table.add(Arrays.asList(argInfo.getKey(), argInfo.getValue().get()));
160         }
161 
162         AptFormat.writeTable(writer, table, "*--+--+");
163 
164         } catch (IOException e) {
165             throw new RuntimeException(e);
166         }
167     }
168 
169     /**
170      * A class to write APT formatted text.
171      */
172     private static class AptFormat  {
173 
174         /**
175          * Copy the "license.apt" from the resources to the writer.
176          * @param writer the writer to write to.
177          * @throws IOException on error.
178          */
179         public static void writeLicense(final Writer writer) throws IOException {
180             try (InputStream in = AntDocumentation.class.getResourceAsStream("/license.apt")) {
181                 if (in == null) {
182                     throw new FileNotFoundException("Could not find license.apt");
183                 }
184                 IOUtils.copy(in, writer, StandardCharsets.UTF_8);
185             }
186         }
187 
188         /**
189          * Write a title.
190          * @param writer the writer to write to.
191          * @param title the title to write.
192          * @throws IOException on error.
193          */
194         public static void writeTitle(final Writer writer, final String title) throws IOException {
195             writer.write(format("        -----%n        %1$s%n        -----%n%n%1$s%n%n", title));
196         }
197 
198         /**
199          * Write a paragraph.
200          * @param writer the writer to write to.
201          * @param paragraph the paragraph to write.
202          * @throws IOException on error.
203          */
204         public static void writePara(final Writer writer, final String paragraph) throws IOException {
205             writer.write(format("  %s%n%n", paragraph));
206         }
207 
208         /**
209          * Write a header.
210          * @param writer the writer to write to.
211          * @param level the level of the header
212          * @param text the text for the header
213          * @throws IOException on error.
214          */
215         public static void writeHeader(final Writer writer, final int level, final String text) throws IOException {
216             writer.write(System.lineSeparator());
217             for (int i = 0; i < level; i++) {
218                 writer.write("*");
219             }
220             writer.write(format(" %s%n%n", text));
221         }
222 
223         /**
224          * Write a list.
225          * @param writer the writer to write to.
226          * @param list the list to write.
227          * @throws IOException on error.
228          */
229         public static void writeList(final Writer writer, final Collection<String> list) throws IOException {
230             for (String s : list) {
231                 writer.write(format("    * %s%n", s));
232             }
233             writer.write(System.lineSeparator());
234         }
235 
236         /**
237          * Write a table.
238          * @param writer the Writer to write to.
239          * @param table the Table to write. A collection of collections of Strings.
240          * @param pattern the pattern before and after the table.
241          * @param caption the caption for the table.
242          * @throws IOException on error.
243          */
244         public static void writeTable(final Writer writer, final Collection<? extends Collection<String>> table,
245                                       final String pattern, final String caption) throws IOException {
246             writer.write(format("%s%n", pattern));
247             for (Collection<String> row : table) {
248                 for (String cell : row) {
249                     writer.write(format("| %s ", cell));
250                 }
251                 writer.write(format("|%n%s%n", pattern));
252             }
253             if (caption != null) {
254                 writer.write(caption);
255             }
256             writer.write(System.lineSeparator());
257         }
258 
259         /**
260          * Write a table entry.
261          * @param writer the Writer to write to.
262          * @param table the Table to write
263          * @param pattern the pattern before and after the table.
264          * @throws IOException on error
265          */
266         public static void writeTable(final Writer writer, final Collection<? extends Collection<String>> table,
267                                       final String pattern) throws IOException {
268             writeTable(writer, table, pattern, null);
269         }
270     }
271 }