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