1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.rat.tools;
20
21 import java.io.CharArrayWriter;
22 import java.io.FileWriter;
23 import java.io.IOException;
24 import java.io.OutputStreamWriter;
25 import java.io.PrintWriter;
26 import java.io.Writer;
27 import java.nio.charset.StandardCharsets;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Deque;
31 import java.util.LinkedList;
32 import java.util.List;
33 import java.util.function.Function;
34 import java.util.function.Predicate;
35
36 import org.apache.commons.cli.CommandLine;
37 import org.apache.commons.cli.DefaultParser;
38 import org.apache.commons.cli.HelpFormatter;
39 import org.apache.commons.cli.Option;
40 import org.apache.commons.cli.Options;
41 import org.apache.commons.cli.ParseException;
42 import org.apache.commons.csv.CSVFormat;
43 import org.apache.commons.csv.CSVPrinter;
44 import org.apache.commons.csv.QuoteMode;
45 import org.apache.commons.lang3.StringUtils;
46 import org.apache.rat.OptionCollection;
47 import org.apache.rat.documentation.options.AntOption;
48 import org.apache.rat.documentation.options.MavenOption;
49 import org.apache.rat.help.AbstractHelp;
50
51
52
53
54
55
56
57
58
59
60
61
62 public final class Naming {
63
64
65 private static final Option WIDTH = Option.builder().longOpt("width").type(Integer.class)
66 .desc("Set the display width of the output").hasArg().build();
67
68 private static final Option MAVEN = Option.builder().longOpt("maven").desc("Produce Maven name mapping").build();
69
70 private static final Option ANT = Option.builder().longOpt("ant").desc("Produce Ant name mapping").build();
71
72 private static final Option CSV = Option.builder().longOpt("csv").desc("Produce CSV format").build();
73
74 private static final Option CLI = Option.builder().longOpt("cli").desc("Produce CLI name mapping").build();
75
76 private static final Option INCLUDE_DEPRECATED = Option.builder().longOpt("include-deprecated")
77 .desc("Include deprecated options.").build();
78
79 private static final Options OPTIONS = new Options().addOption(MAVEN).addOption(ANT).addOption(CLI)
80 .addOption(CSV)
81 .addOption(INCLUDE_DEPRECATED)
82 .addOption(WIDTH);
83
84
85
86
87 private Naming() { }
88
89
90
91
92
93
94
95
96
97
98
99 public static void main(final String[] args) throws IOException, ParseException {
100 if (args == null || args.length < 1) {
101 System.err.println("At least one argument is required: path to file is missing.");
102 return;
103 }
104 CommandLine cl = DefaultParser.builder().build().parse(OPTIONS, args);
105 int width = Math.max(cl.getParsedOptionValue(WIDTH, AbstractHelp.HELP_WIDTH), AbstractHelp.HELP_WIDTH);
106
107 boolean showMaven = cl.hasOption(MAVEN);
108
109 boolean showAnt = cl.hasOption(ANT);
110 boolean includeDeprecated = cl.hasOption(INCLUDE_DEPRECATED);
111 Predicate<Option> filter = o -> o.hasLongOpt() && (!o.isDeprecated() || includeDeprecated);
112
113 List<String> columns = new ArrayList<>();
114
115 if (cl.hasOption(CLI)) {
116 columns.add("CLI");
117 }
118
119 if (showAnt) {
120 columns.add("Ant");
121 }
122
123 if (showMaven) {
124 columns.add("Maven");
125 }
126 columns.add("Description");
127 columns.add("Argument Type");
128
129 Function<Option, String> descriptionFunction;
130
131 if (cl.hasOption(CLI) || !showAnt && !showMaven) {
132 descriptionFunction = o -> {
133 StringBuilder desc = new StringBuilder();
134 if (o.isDeprecated()) {
135 desc.append("[").append(o.getDeprecated().toString()).append("] ");
136 }
137 return desc.append(StringUtils.defaultIfEmpty(o.getDescription(), "")).toString();
138 };
139 } else if (showAnt) {
140 descriptionFunction = o -> {
141 StringBuilder desc = new StringBuilder();
142 AntOption antOption = new AntOption(o);
143 if (antOption.isDeprecated()) {
144 desc.append("[").append(antOption.getDeprecated()).append("] ");
145 }
146 return desc.append(StringUtils.defaultIfEmpty(antOption.getDescription(), "")).toString();
147 };
148 } else {
149 descriptionFunction = o -> {
150 StringBuilder desc = new StringBuilder();
151 MavenOption mavenOption = new MavenOption(o);
152 if (mavenOption.isDeprecated()) {
153 desc.append("[").append(mavenOption.getDeprecated()).append("] ");
154 }
155 return desc.append(StringUtils.defaultIfEmpty(mavenOption.getDescription(), "")).toString();
156 };
157 }
158
159 try (Writer underWriter = cl.getArgs().length != 0 ?
160 new FileWriter(cl.getArgs()[0], StandardCharsets.UTF_8) : new OutputStreamWriter(System.out, StandardCharsets.UTF_8)) {
161 if (cl.hasOption(CSV)) {
162 printCSV(columns, filter, cl.hasOption(CLI), showMaven, showAnt, descriptionFunction, underWriter);
163 }
164 else {
165 printText(columns, filter, cl.hasOption(CLI), showMaven, showAnt, descriptionFunction, underWriter, width);
166 }
167 }
168 }
169
170 private static List<String> fillColumns(final List<String> columns, final Option option, final boolean addCLI, final boolean showMaven,
171 final boolean showAnt, final Function<Option, String> descriptionFunction) {
172 if (addCLI) {
173 if (option.hasLongOpt()) {
174 columns.add("--" + option.getLongOpt());
175 } else {
176 columns.add("-" + option.getOpt());
177 }
178 }
179 if (showAnt) {
180 columns.add(new AntOption(option).getExample());
181 }
182 if (showMaven) {
183 columns.add(new MavenOption(option).getExample());
184 }
185
186 columns.add(descriptionFunction.apply(option));
187 columns.add(option.hasArgName() ? option.getArgName() : option.hasArgs() ? "Strings" : option.hasArg() ? "String" : "-- none --");
188 columns.add(option.hasArgName() ? option.getArgName() : option.hasArgs() ? "Strings" : option.hasArg() ? "String" : "-- none --");
189 columns.add(option.hasArgName() ? option.getArgName() : option.hasArgs() ? "Strings" : option.hasArg() ? "String" : "-- none --");
190 return columns;
191 }
192
193 private static void printCSV(final List<String> columns, final Predicate<Option> filter, final boolean addCLI, final boolean showMaven,
194 final boolean showAnt, final Function<Option, String> descriptionFunction,
195 final Writer underWriter) throws IOException {
196 try (CSVPrinter printer = new CSVPrinter(underWriter, CSVFormat.DEFAULT.builder().setQuoteMode(QuoteMode.ALL).get())) {
197 printer.printRecord(columns);
198 for (Option option : OptionCollection.buildOptions().getOptions()) {
199 if (filter.test(option)) {
200 columns.clear();
201 printer.printRecord(fillColumns(columns, option, addCLI, showMaven, showAnt, descriptionFunction));
202 }
203 }
204 }
205 }
206
207 private static int[] calculateColumnWidth(final int width, final int columnCount, final List<List<String>> page) {
208 int[] columnWidth = new int[columnCount];
209 for (List<String> row : page) {
210 for (int i = 0; i < columnCount; i++) {
211 columnWidth[i] = Math.max(columnWidth[i], row.get(i).length());
212 }
213 }
214 int extra = 0;
215 int averageWidth = (width - ((columnCount - 1) * 2)) / columnCount;
216 int[] overage = new int[columnCount];
217 int totalOverage = 0;
218 for (int i = 0; i < columnCount; i++) {
219 if (columnWidth[i] < averageWidth) {
220 extra += averageWidth - columnWidth[i];
221 } else if (columnWidth[i] > averageWidth) {
222 overage[i] = columnWidth[i] - averageWidth;
223 totalOverage += overage[i];
224 }
225 }
226
227 for (int i = 0; i < columnCount; i++) {
228 if (overage[i] > 0) {
229 int addl = (int) (extra * overage[i] * 1.0 / totalOverage);
230 columnWidth[i] = averageWidth + addl;
231 }
232 }
233 return columnWidth;
234 }
235
236 private static void printText(final List<String> columns, final Predicate<Option> filter, final boolean addCLI,
237 final boolean showMaven, final boolean showAnt,
238 final Function<Option, String> descriptionFunction, final Writer underWriter, final int width) throws IOException {
239 List<List<String>> page = new ArrayList<>();
240
241 int columnCount = columns.size();
242 page.add(columns);
243
244 for (Option option : OptionCollection.buildOptions().getOptions()) {
245 if (filter.test(option)) {
246 page.add(fillColumns(new ArrayList<>(), option, addCLI, showMaven, showAnt, descriptionFunction));
247 }
248 }
249 int[] columnWidth = calculateColumnWidth(width, columnCount, page);
250 HelpFormatter helpFormatter;
251 helpFormatter = new HelpFormatter.Builder().get();
252 helpFormatter.setWidth(width);
253
254
255 List<Deque<String>> entries = new ArrayList<>();
256 CharArrayWriter cWriter = new CharArrayWriter();
257
258
259 for (List<String> cols : page) {
260 entries.clear();
261 PrintWriter writer = new PrintWriter(cWriter);
262
263 for (int i = 0; i < columnCount; i++) {
264 String col = cols.get(i);
265
266 for (String line : col.split("\\v")) {
267 helpFormatter.printWrapped(writer, columnWidth[i], 2, line);
268 }
269 writer.flush();
270
271 Deque<String> entryLines = new LinkedList<>(Arrays.asList(cWriter.toString().split("\\v")));
272
273 entries.add(entryLines);
274 cWriter.reset();
275 }
276
277 boolean cont = true;
278 while (cont) {
279 cont = false;
280 for (int columnNumber = 0; columnNumber < entries.size(); columnNumber++) {
281 Deque<String> queue = entries.get(columnNumber);
282 if (queue.isEmpty()) {
283 underWriter.append(AbstractHelp.createPadding(columnWidth[columnNumber] + 2));
284 } else {
285 String ln = queue.pop();
286 underWriter.append(ln);
287 underWriter.append(AbstractHelp.createPadding(columnWidth[columnNumber] - ln.length() + 2));
288 if (!queue.isEmpty()) {
289 cont = true;
290 }
291 }
292 }
293 underWriter.append(System.lineSeparator());
294 }
295 underWriter.append(System.lineSeparator());
296 }
297 }
298 }